Skip to main content

facet_reflect/partial/
typeplan.rs

1//! TypePlan: Precomputed deserialization plans for types.
2//!
3//! Instead of repeatedly inspecting Shape/Def at runtime during deserialization,
4//! we build a plan tree once that encodes all the decisions we'll make.
5//!
6//! This design:
7//! - Avoids self-referential structs (TypePlan owns its arenas)
8//! - Allows reusing the plan across multiple deserializations
9//! - Uses 32-bit indices for compact representation
10
11use alloc::sync::Arc;
12use alloc::vec::Vec;
13
14use facet_core::{
15    Characteristic, ConstTypeId, Def, DefaultInPlaceFn, DefaultSource, EnumType, Field, ProxyDef,
16    ScalarType, SequenceType, Shape, StructType, Type, UserType, ValidatorFn, Variant,
17};
18use hashbrown::HashMap;
19use smallvec::SmallVec;
20
21use super::arena::{Arena, Idx, SliceRange};
22use crate::AllocError;
23
24#[cfg(feature = "std")]
25#[allow(clippy::std_instead_of_core)]
26fn type_plan_cache() -> &'static std::sync::Mutex<HashMap<&'static Shape, Arc<TypePlanCore>>> {
27    use std::sync::{Mutex, OnceLock};
28
29    static PLAN_CACHE: OnceLock<Mutex<HashMap<&'static Shape, Arc<TypePlanCore>>>> =
30        OnceLock::new();
31    PLAN_CACHE.get_or_init(|| Mutex::new(HashMap::new()))
32}
33
34/// Type alias for node indices in the TypePlan.
35pub type NodeId = Idx<TypePlanNode>;
36
37/// Type alias for field plan slice ranges.
38pub type FieldRange = SliceRange<FieldPlan>;
39
40/// Type alias for variant plan slice ranges.
41pub type VariantRange = SliceRange<VariantPlanMeta>;
42
43/// Type alias for validator slice ranges.
44pub type ValidatorRange = SliceRange<PrecomputedValidator>;
45
46/// Precomputed deserialization plan tree for a type.
47///
48/// Built once from a Shape, this encodes all decisions needed during deserialization
49/// without repeated runtime lookups. The `TypePlan` owns all its allocations through
50/// internal arenas.
51///
52/// The type parameter `T` is phantom and provides compile-time type safety:
53/// you cannot accidentally pass a `TypePlan<Foo>` where `TypePlan<Bar>` is expected.
54/// There is no public way to erase the type parameter.
55#[derive(Debug)]
56pub struct TypePlan<T: ?Sized> {
57    /// The actual plan data (type-erased internally)
58    core: Arc<TypePlanCore>,
59    /// Phantom type parameter for compile-time type safety
60    _marker: core::marker::PhantomData<fn() -> T>,
61}
62
63/// Type-erased plan data that owns all allocations.
64///
65/// This is what `Partial` actually stores a reference to. The type safety comes from
66/// the `TypePlan<T>` wrapper at the API boundary.
67///
68/// Users should build plans using `TypePlan::<T>::build()` which provides
69/// type safety.
70#[derive(Debug)]
71pub struct TypePlanCore {
72    /// Arena of type plan nodes
73    nodes: Arena<TypePlanNode>,
74    /// Arena of field plans (for structs and enum variants)
75    fields: Arena<FieldPlan>,
76    /// Arena of variant metadata (for enums)
77    variants: Arena<VariantPlanMeta>,
78    /// Arena of precomputed validators
79    validators: Arena<PrecomputedValidator>,
80    /// Arena of field lookup entries
81    field_entries: Arena<FieldLookupEntry>,
82    /// Arena of bucket tuples for prefix-based lookup
83    buckets: Arena<(u64, u32, u32)>,
84    /// Sorted lookup table for resolving BackRef nodes by TypeId.
85    node_lookup: Vec<(ConstTypeId, NodeId)>,
86    /// Root node index
87    root: NodeId,
88}
89
90/// A node in the TypePlan tree.
91#[derive(Debug)]
92pub struct TypePlanNode {
93    /// The shape this node was built from
94    pub shape: &'static Shape,
95    /// What kind of type this is and how to deserialize it
96    pub kind: TypePlanNodeKind,
97    /// Precomputed deserialization strategy - tells facet-format exactly what to do
98    pub strategy: DeserStrategy,
99    /// Whether this type has a Default implementation
100    pub has_default: bool,
101    /// Precomputed proxy nodes for this shape.
102    ///
103    /// Contains nodes for all proxies (format-agnostic and format-specific),
104    /// allowing runtime lookup based on the deserializer's format namespace.
105    pub proxies: ProxyNodes,
106}
107
108/// Precomputed proxy node info - stores TypePlan nodes for all proxies on a type/field.
109///
110/// This enables a single TypePlan to work with any format by deferring proxy selection
111/// to runtime while still having precomputed TypePlan nodes for each proxy type.
112#[derive(Debug, Clone, Default)]
113pub struct ProxyNodes {
114    /// Format-agnostic proxy node (from `#[facet(proxy = X)]`)
115    pub generic: Option<NodeId>,
116    /// Format-specific proxy nodes (from `#[facet(json::proxy = X)]` etc.)
117    /// Stored as (format_namespace, node_id) pairs.
118    pub format_specific: SmallVec<(&'static str, NodeId), 2>,
119}
120
121impl ProxyNodes {
122    /// Look up the proxy node for a given format namespace.
123    ///
124    /// Resolution order:
125    /// 1. Format-specific proxy if format is provided and matches
126    /// 2. Format-agnostic proxy as fallback
127    #[inline]
128    pub fn node_for(&self, format: Option<&str>) -> Option<NodeId> {
129        if let Some(fmt) = format {
130            // First try format-specific
131            if let Some((_, node)) = self.format_specific.iter().find(|(f, _)| *f == fmt) {
132                return Some(*node);
133            }
134        }
135        // Fall back to generic
136        self.generic
137    }
138
139    /// Returns true if any proxy exists (generic or format-specific).
140    #[inline]
141    pub fn has_any(&self) -> bool {
142        self.generic.is_some() || !self.format_specific.is_empty()
143    }
144
145    /// Returns true if this is empty (no proxies).
146    #[inline]
147    pub fn is_empty(&self) -> bool {
148        self.generic.is_none() && self.format_specific.is_empty()
149    }
150}
151
152/// Field-level proxy information collected from a Field.
153///
154/// Used during TypePlan building to pass all proxy information for a field.
155#[derive(Debug, Clone)]
156struct FieldProxies {
157    /// Format-agnostic proxy (from `#[facet(proxy = X)]` on the field)
158    generic: Option<&'static ProxyDef>,
159    /// Format-specific proxies (from `#[facet(json::proxy = X)]` etc. on the field)
160    format_specific: SmallVec<(&'static str, &'static ProxyDef), 2>,
161}
162
163impl FieldProxies {
164    /// Collect all proxies from a field.
165    fn from_field(field: &'static Field) -> Option<Self> {
166        let generic = field.proxy();
167        let format_specific: SmallVec<_, 2> = field
168            .format_proxies
169            .iter()
170            .map(|fp| (fp.format, fp.proxy))
171            .collect();
172
173        if generic.is_none() && format_specific.is_empty() {
174            None
175        } else {
176            Some(Self {
177                generic,
178                format_specific,
179            })
180        }
181    }
182}
183
184/// Precomputed deserialization strategy with all data needed to execute it.
185///
186/// This is denormalized: we store node indices, proxy defs, etc. directly so the
187/// deserializer can follow the plan without chasing pointers through Shape/vtable.
188#[derive(Debug)]
189pub enum DeserStrategy {
190    /// Container-level proxy: the type itself has `#[facet(proxy = X)]` or format-specific proxies.
191    ///
192    /// The actual proxy definition and node are looked up at runtime via:
193    /// - `shape.effective_proxy(format_namespace)` for the ProxyDef
194    /// - `node.proxies.node_for(format_namespace)` for the TypePlan node
195    ContainerProxy,
196    /// Field-level proxy: the field has `#[facet(proxy = X)]` but the type doesn't.
197    ///
198    /// The actual proxy definition and node are looked up at runtime via:
199    /// - `field.effective_proxy(format_namespace)` for the ProxyDef
200    /// - `node.proxies.node_for(format_namespace)` for the TypePlan node (from parent's FieldPlan)
201    FieldProxy,
202    /// Smart pointer (Box, Arc, Rc) with known pointee type
203    Pointer {
204        /// The pointee type's plan
205        pointee_node: NodeId,
206    },
207    /// Opaque smart pointer (`#[facet(opaque)]`) - cannot be deserialized, only set wholesale
208    OpaquePointer,
209    /// Opaque type (`Opaque<T>`) - cannot be deserialized, only set wholesale via proxy
210    Opaque,
211    /// Transparent wrapper with try_from (like NonZero)
212    TransparentConvert {
213        /// The inner type's plan
214        inner_node: NodeId,
215    },
216    /// Scalar with FromStr
217    Scalar {
218        /// Precomputed scalar type for fast hint dispatch.
219        /// None for opaque scalars that need parser-specific handling.
220        scalar_type: Option<ScalarType>,
221        /// Whether this scalar type implements FromStr (for string parsing fallback)
222        is_from_str: bool,
223    },
224    /// Named struct
225    Struct,
226    /// Tuple or tuple struct
227    Tuple {
228        /// Number of fields in the tuple
229        field_count: usize,
230        /// Whether this is a single-field transparent wrapper that can accept values directly
231        is_single_field_transparent: bool,
232    },
233    /// Enum
234    Enum,
235    /// `Option<T>`
236    Option {
237        /// The Some variant's inner type plan
238        some_node: NodeId,
239    },
240    /// `Result<T, E>`
241    Result {
242        /// The Ok variant's type plan
243        ok_node: NodeId,
244        /// The Err variant's type plan
245        err_node: NodeId,
246    },
247    /// List (Vec, VecDeque, etc.)
248    List {
249        /// The item type's plan
250        item_node: NodeId,
251        /// Whether this is specifically `Vec<u8>` (for optimized byte sequence handling)
252        is_byte_vec: bool,
253    },
254    /// Map (HashMap, BTreeMap, etc.)
255    Map {
256        /// The key type's plan
257        key_node: NodeId,
258        /// The value type's plan
259        value_node: NodeId,
260    },
261    /// Set (HashSet, BTreeSet, etc.)
262    Set {
263        /// The item type's plan
264        item_node: NodeId,
265    },
266    /// Fixed-size array [T; N]
267    Array {
268        /// Array length
269        len: usize,
270        /// The item type's plan
271        item_node: NodeId,
272    },
273    /// DynamicValue (like `facet_value::Value`)
274    DynamicValue,
275    /// Metadata container (like `Spanned<T>`, `Documented<T>`)
276    /// These require special field-by-field handling for metadata population
277    MetadataContainer,
278    /// BackRef to recursive type - resolved via TypePlan::resolve_backref()
279    BackRef {
280        /// The TypeId of the target node
281        target_type_id: ConstTypeId,
282    },
283}
284
285/// The specific kind of type and its deserialization strategy.
286#[derive(Debug)]
287#[allow(clippy::large_enum_variant)] // Struct/Enum variants are intentionally large
288pub enum TypePlanNodeKind {
289    /// Scalar types (integers, floats, bool, char, strings)
290    Scalar,
291
292    /// Struct types with named or positional fields
293    Struct(StructPlan),
294
295    /// Enum types with variants
296    Enum(EnumPlan),
297
298    /// `Option<T>` - special handling for None/Some
299    Option,
300
301    /// `Result<T, E>` - special handling for Ok/Err
302    Result,
303
304    /// `Vec<T>`, `VecDeque<T>`, etc.
305    List,
306
307    /// Slice types `[T]` (unsized, used via smart pointers like `Arc<[T]>`)
308    Slice,
309
310    /// `HashMap<K, V>`, `BTreeMap<K, V>`, etc.
311    Map,
312
313    /// `HashSet<T>`, `BTreeSet<T>`, etc.
314    Set,
315
316    /// Fixed-size arrays `[T; N]`
317    Array {
318        /// Array length N
319        len: usize,
320    },
321
322    /// Smart pointers: `Box<T>`, `Arc<T>`, `Rc<T>`
323    Pointer,
324
325    /// Opaque smart pointers (`#[facet(opaque)]`)
326    OpaquePointer,
327
328    /// Opaque types (`Opaque<T>`) - can only be set wholesale, not deserialized
329    Opaque,
330
331    /// DynamicValue (like `serde_json::Value`)
332    DynamicValue,
333
334    /// Transparent wrappers (newtypes)
335    Transparent,
336
337    /// Back-reference to an ancestor node (for recursive types)
338    /// Resolved via TypePlan::resolve_backref()
339    BackRef(ConstTypeId),
340}
341
342/// Precomputed plan for struct deserialization.
343#[derive(Debug)]
344pub struct StructPlan {
345    /// Reference to the struct type definition
346    pub struct_def: &'static StructType,
347    /// Complete plans for each field, indexed by field position.
348    /// Combines matching metadata with initialization/validation info.
349    pub fields: FieldRange,
350    /// Fast field lookup by name
351    pub field_lookup: FieldLookup,
352    /// Whether any field has #[facet(flatten)]
353    pub has_flatten: bool,
354    /// Whether to reject unknown fields (precomputed from `#[facet(deny_unknown_fields)]`)
355    pub deny_unknown_fields: bool,
356}
357
358/// Complete precomputed plan for a single field.
359///
360/// Combines field matching metadata (name, aliases, type node) with
361/// initialization/validation info (fill rule, validators, offset).
362#[derive(Debug, Clone)]
363pub struct FieldPlan {
364    // --- Metadata for matching/lookup ---
365    /// Reference to the field definition
366    pub field: &'static Field,
367    /// Field name (for path tracking and error messages)
368    pub name: &'static str,
369    /// The name to match in input (considers rename)
370    pub effective_name: &'static str,
371    /// Alias if any
372    pub alias: Option<&'static str>,
373    /// Whether this field is flattened
374    pub is_flattened: bool,
375    /// This field's type plan node index
376    pub type_node: NodeId,
377
378    // --- Initialization/validation ---
379    /// Field index in the struct (for ISet tracking)
380    pub index: usize,
381    /// Field offset in bytes from struct base (for calculating field pointer)
382    pub offset: usize,
383    /// The field's type shape (for reading values during validation)
384    pub field_shape: &'static Shape,
385    /// How to handle this field if not set during deserialization
386    pub fill_rule: FillRule,
387    /// Validators to run after the field is set (precomputed from attributes)
388    pub validators: ValidatorRange,
389}
390
391impl FieldPlan {
392    /// Returns true if this field has a default value.
393    #[inline]
394    pub fn has_default(&self) -> bool {
395        matches!(self.fill_rule, FillRule::Defaultable(_))
396    }
397
398    /// Returns true if this field is required (no default, not Option).
399    #[inline]
400    pub fn is_required(&self) -> bool {
401        matches!(self.fill_rule, FillRule::Required)
402    }
403}
404
405/// Type alias for backwards compatibility with code expecting FieldInitPlan.
406pub type FieldInitPlan = FieldPlan;
407
408/// How to fill a field that wasn't set during deserialization.
409#[derive(Debug, Clone)]
410pub enum FillRule {
411    /// Field has a default - call this function if not set.
412    /// The function writes the default value to an uninitialized pointer.
413    Defaultable(FieldDefault),
414    /// Field is required - error if not set.
415    Required,
416}
417
418/// Source of default value for a field.
419#[derive(Debug, Clone, Copy)]
420pub enum FieldDefault {
421    /// Use a custom default function (from `#[facet(default = expr)]`)
422    Custom(DefaultInPlaceFn),
423    /// Use the type's Default trait (via shape.call_default_in_place)
424    /// We store the shape so we can call its default_in_place
425    FromTrait(&'static Shape),
426}
427
428/// A precomputed validator extracted from field attributes.
429#[derive(Debug, Clone)]
430pub struct PrecomputedValidator {
431    /// The validator kind with any associated data
432    pub kind: ValidatorKind,
433}
434
435impl PrecomputedValidator {
436    /// Run this validator on an initialized field value.
437    ///
438    /// # Safety
439    /// `field_ptr` must point to initialized memory of the type specified by the validator's scalar_type.
440    #[allow(unsafe_code)]
441    pub fn run(
442        &self,
443        field_ptr: facet_core::PtrConst,
444        field_name: &'static str,
445        container_shape: &'static Shape,
446    ) -> Result<(), crate::ReflectErrorKind> {
447        use crate::ReflectErrorKind;
448        use alloc::format;
449
450        let result: Result<(), alloc::string::String> = match self.kind {
451            ValidatorKind::Custom(validator_fn) => {
452                // SAFETY: caller guarantees field_ptr points to valid data
453                unsafe { validator_fn(field_ptr) }
454            }
455            ValidatorKind::Min { limit, scalar_type } => {
456                Self::validate_min(field_ptr, limit, scalar_type)
457            }
458            ValidatorKind::Max { limit, scalar_type } => {
459                Self::validate_max(field_ptr, limit, scalar_type)
460            }
461            ValidatorKind::MinLength { limit, scalar_type } => {
462                let len = Self::get_string_length(field_ptr, scalar_type);
463                if len < limit {
464                    Err(format!("length must be >= {}, got {}", limit, len))
465                } else {
466                    Ok(())
467                }
468            }
469            ValidatorKind::MaxLength { limit, scalar_type } => {
470                let len = Self::get_string_length(field_ptr, scalar_type);
471                if len > limit {
472                    Err(format!("length must be <= {}, got {}", limit, len))
473                } else {
474                    Ok(())
475                }
476            }
477            ValidatorKind::Email { scalar_type } => {
478                let s = unsafe { Self::get_string(field_ptr, scalar_type) };
479                if Self::is_valid_email(s) {
480                    Ok(())
481                } else {
482                    Err(format!("'{}' is not a valid email address", s))
483                }
484            }
485            ValidatorKind::Url { scalar_type } => {
486                let s = unsafe { Self::get_string(field_ptr, scalar_type) };
487                if Self::is_valid_url(s) {
488                    Ok(())
489                } else {
490                    Err(format!("'{}' is not a valid URL", s))
491                }
492            }
493            ValidatorKind::Regex {
494                pattern,
495                scalar_type,
496            } => {
497                let s = unsafe { Self::get_string(field_ptr, scalar_type) };
498                if Self::matches_pattern(s, pattern) {
499                    Ok(())
500                } else {
501                    Err(format!("'{}' does not match pattern '{}'", s, pattern))
502                }
503            }
504            ValidatorKind::Contains {
505                needle,
506                scalar_type,
507            } => {
508                let s = unsafe { Self::get_string(field_ptr, scalar_type) };
509                if s.contains(needle) {
510                    Ok(())
511                } else {
512                    Err(format!("'{}' does not contain '{}'", s, needle))
513                }
514            }
515        };
516
517        result.map_err(|message| ReflectErrorKind::ValidationFailed {
518            shape: container_shape,
519            field_name,
520            message,
521        })
522    }
523
524    #[allow(unsafe_code)]
525    fn validate_min(
526        field_ptr: facet_core::PtrConst,
527        limit: i64,
528        scalar_type: ScalarType,
529    ) -> Result<(), alloc::string::String> {
530        use alloc::format;
531        match scalar_type {
532            ScalarType::I8 => {
533                let v = unsafe { *field_ptr.get::<i8>() } as i64;
534                if v < limit {
535                    Err(format!("must be >= {}, got {}", limit, v))
536                } else {
537                    Ok(())
538                }
539            }
540            ScalarType::I16 => {
541                let v = unsafe { *field_ptr.get::<i16>() } as i64;
542                if v < limit {
543                    Err(format!("must be >= {}, got {}", limit, v))
544                } else {
545                    Ok(())
546                }
547            }
548            ScalarType::I32 => {
549                let v = unsafe { *field_ptr.get::<i32>() } as i64;
550                if v < limit {
551                    Err(format!("must be >= {}, got {}", limit, v))
552                } else {
553                    Ok(())
554                }
555            }
556            ScalarType::I64 => {
557                let v = unsafe { *field_ptr.get::<i64>() };
558                if v < limit {
559                    Err(format!("must be >= {}, got {}", limit, v))
560                } else {
561                    Ok(())
562                }
563            }
564            ScalarType::U8 => {
565                let v = unsafe { *field_ptr.get::<u8>() } as i64;
566                if v < limit {
567                    Err(format!("must be >= {}, got {}", limit, v))
568                } else {
569                    Ok(())
570                }
571            }
572            ScalarType::U16 => {
573                let v = unsafe { *field_ptr.get::<u16>() } as i64;
574                if v < limit {
575                    Err(format!("must be >= {}, got {}", limit, v))
576                } else {
577                    Ok(())
578                }
579            }
580            ScalarType::U32 => {
581                let v = unsafe { *field_ptr.get::<u32>() } as i64;
582                if v < limit {
583                    Err(format!("must be >= {}, got {}", limit, v))
584                } else {
585                    Ok(())
586                }
587            }
588            ScalarType::U64 => {
589                let v = unsafe { *field_ptr.get::<u64>() };
590                if v > i64::MAX as u64 {
591                    Ok(()) // Value too large to compare as i64, assume valid for min
592                } else if (v as i64) < limit {
593                    Err(format!("must be >= {}, got {}", limit, v))
594                } else {
595                    Ok(())
596                }
597            }
598            _ => Ok(()), // Non-numeric type - should not happen if TypePlan is built correctly
599        }
600    }
601
602    #[allow(unsafe_code)]
603    fn validate_max(
604        field_ptr: facet_core::PtrConst,
605        limit: i64,
606        scalar_type: ScalarType,
607    ) -> Result<(), alloc::string::String> {
608        use alloc::format;
609        match scalar_type {
610            ScalarType::I8 => {
611                let v = unsafe { *field_ptr.get::<i8>() } as i64;
612                if v > limit {
613                    Err(format!("must be <= {}, got {}", limit, v))
614                } else {
615                    Ok(())
616                }
617            }
618            ScalarType::I16 => {
619                let v = unsafe { *field_ptr.get::<i16>() } as i64;
620                if v > limit {
621                    Err(format!("must be <= {}, got {}", limit, v))
622                } else {
623                    Ok(())
624                }
625            }
626            ScalarType::I32 => {
627                let v = unsafe { *field_ptr.get::<i32>() } as i64;
628                if v > limit {
629                    Err(format!("must be <= {}, got {}", limit, v))
630                } else {
631                    Ok(())
632                }
633            }
634            ScalarType::I64 => {
635                let v = unsafe { *field_ptr.get::<i64>() };
636                if v > limit {
637                    Err(format!("must be <= {}, got {}", limit, v))
638                } else {
639                    Ok(())
640                }
641            }
642            ScalarType::U8 => {
643                let v = unsafe { *field_ptr.get::<u8>() } as i64;
644                if v > limit {
645                    Err(format!("must be <= {}, got {}", limit, v))
646                } else {
647                    Ok(())
648                }
649            }
650            ScalarType::U16 => {
651                let v = unsafe { *field_ptr.get::<u16>() } as i64;
652                if v > limit {
653                    Err(format!("must be <= {}, got {}", limit, v))
654                } else {
655                    Ok(())
656                }
657            }
658            ScalarType::U32 => {
659                let v = unsafe { *field_ptr.get::<u32>() } as i64;
660                if v > limit {
661                    Err(format!("must be <= {}, got {}", limit, v))
662                } else {
663                    Ok(())
664                }
665            }
666            ScalarType::U64 => {
667                let v = unsafe { *field_ptr.get::<u64>() };
668                // Check if v exceeds limit: either v > i64::MAX (always fails for positive limit)
669                // or v fits in i64 and exceeds limit
670                if v > i64::MAX as u64 || (v as i64) > limit {
671                    Err(format!("must be <= {}, got {}", limit, v))
672                } else {
673                    Ok(())
674                }
675            }
676            _ => Ok(()), // Non-numeric type - should not happen if TypePlan is built correctly
677        }
678    }
679
680    #[allow(unsafe_code)]
681    fn get_string_length(field_ptr: facet_core::PtrConst, scalar_type: ScalarType) -> usize {
682        // SAFETY: caller guarantees field_ptr points to valid string data
683        unsafe {
684            match scalar_type {
685                ScalarType::String => (*field_ptr.get::<alloc::string::String>()).len(),
686                ScalarType::CowStr => (*field_ptr.get::<alloc::borrow::Cow<'_, str>>()).len(),
687                _ => 0, // Non-string type
688            }
689        }
690    }
691
692    /// # Safety
693    /// `field_ptr` must point to initialized memory of the given scalar_type.
694    /// The returned reference is only valid while the pointed-to memory is valid.
695    #[allow(unsafe_code)]
696    unsafe fn get_string(field_ptr: facet_core::PtrConst, scalar_type: ScalarType) -> &'static str {
697        // SAFETY: The caller guarantees field_ptr points to valid memory.
698        // We transmute the lifetime to 'static because we need to return a reference
699        // but don't have a lifetime to bind it to. The caller must ensure the reference
700        // is not used after the pointed-to memory is invalidated.
701        match scalar_type {
702            ScalarType::String => {
703                let s: &str = unsafe { (*field_ptr.get::<alloc::string::String>()).as_str() };
704                // SAFETY: The caller ensures the pointed-to memory remains valid for the returned lifetime.
705                unsafe { core::mem::transmute::<&str, &'static str>(s) }
706            }
707            ScalarType::CowStr => {
708                let s: &str = unsafe { (*field_ptr.get::<alloc::borrow::Cow<'_, str>>()).as_ref() };
709                // SAFETY: The caller ensures the pointed-to memory remains valid for the returned lifetime.
710                unsafe { core::mem::transmute::<&str, &'static str>(s) }
711            }
712            _ => "", // Non-string type
713        }
714    }
715
716    fn is_valid_email(s: &str) -> bool {
717        // Simple email validation: contains exactly one @ with text on both sides
718        let parts: Vec<&str> = s.split('@').collect();
719        parts.len() == 2 && !parts[0].is_empty() && !parts[1].is_empty() && parts[1].contains('.')
720    }
721
722    fn is_valid_url(s: &str) -> bool {
723        // Simple URL validation: starts with http:// or https://
724        s.starts_with("http://") || s.starts_with("https://")
725    }
726
727    fn matches_pattern(s: &str, pattern: &str) -> bool {
728        // Use regex crate if available, otherwise basic substring match
729        #[cfg(feature = "regex")]
730        {
731            regex::Regex::new(pattern)
732                .map(|re| re.is_match(s))
733                .unwrap_or(false)
734        }
735        #[cfg(not(feature = "regex"))]
736        {
737            // Fallback: treat pattern as literal substring
738            s.contains(pattern)
739        }
740    }
741}
742
743/// The kind of validation to perform on a field.
744#[derive(Debug, Clone, Copy)]
745pub enum ValidatorKind {
746    /// Custom validator function
747    Custom(ValidatorFn),
748    /// Minimum value (for numeric types)
749    Min {
750        /// The minimum allowed value
751        limit: i64,
752        /// How to read the value from memory
753        scalar_type: ScalarType,
754    },
755    /// Maximum value (for numeric types)
756    Max {
757        /// The maximum allowed value
758        limit: i64,
759        /// How to read the value from memory
760        scalar_type: ScalarType,
761    },
762    /// Minimum length (for strings)
763    MinLength {
764        /// The minimum allowed length
765        limit: usize,
766        /// How to read the string from memory
767        scalar_type: ScalarType,
768    },
769    /// Maximum length (for strings)
770    MaxLength {
771        /// The maximum allowed length
772        limit: usize,
773        /// How to read the string from memory
774        scalar_type: ScalarType,
775    },
776    /// Must be valid email
777    Email {
778        /// How to read the string from memory
779        scalar_type: ScalarType,
780    },
781    /// Must be valid URL
782    Url {
783        /// How to read the string from memory
784        scalar_type: ScalarType,
785    },
786    /// Must match regex pattern
787    Regex {
788        /// The regex pattern to match
789        pattern: &'static str,
790        /// How to read the string from memory
791        scalar_type: ScalarType,
792    },
793    /// Must contain substring
794    Contains {
795        /// The substring to search for
796        needle: &'static str,
797        /// How to read the string from memory
798        scalar_type: ScalarType,
799    },
800}
801
802/// Precomputed plan for enum deserialization.
803#[derive(Debug)]
804pub struct EnumPlan {
805    /// Reference to the enum type definition
806    pub enum_def: &'static EnumType,
807    /// Plans for each variant
808    pub variants: VariantRange,
809    /// Fast variant lookup by name
810    pub variant_lookup: VariantLookup,
811    /// Number of variants
812    pub num_variants: usize,
813    /// Index of the `#[facet(other)]` variant, if any
814    pub other_variant_idx: Option<usize>,
815}
816
817/// Metadata for a single enum variant.
818#[derive(Debug, Clone)]
819pub struct VariantPlanMeta {
820    /// Reference to the variant definition
821    pub variant: &'static Variant,
822    /// Variant name
823    pub name: &'static str,
824    /// Complete field plans for this variant
825    pub fields: FieldRange,
826    /// Fast field lookup for this variant
827    pub field_lookup: FieldLookup,
828    /// Whether any field in this variant has #[facet(flatten)]
829    pub has_flatten: bool,
830}
831
832/// Fast lookup from field name to field index.
833///
834/// Uses different strategies based on field count:
835/// - Small (≤8 fields): linear scan (cache-friendly, no hashing overhead)
836/// - Large (>8 fields): prefix-based dispatch (like JIT) - group by first N bytes
837#[derive(Debug, Clone)]
838#[allow(clippy::large_enum_variant)] // SmallVec is intentionally inline
839pub enum FieldLookup {
840    /// For small structs: just store (name, index) pairs
841    /// Capped at LOOKUP_THRESHOLD (8) entries, so we inline all of them.
842    Small(SmallVec<FieldLookupEntry, 16>),
843    /// For larger structs: prefix-based buckets
844    /// Entries are grouped by their N-byte prefix, buckets sorted by prefix for binary search
845    PrefixBuckets {
846        /// Prefix length in bytes (4 or 8)
847        prefix_len: usize,
848        /// All entries, grouped by prefix (range into field_entries arena)
849        entries: SliceRange<FieldLookupEntry>,
850        /// (prefix, start_index, count) sorted by prefix (range into buckets arena)
851        buckets: SliceRange<(u64, u32, u32)>,
852    },
853}
854
855/// An entry in the field lookup table.
856#[derive(Debug, Clone)]
857pub struct FieldLookupEntry {
858    /// The name to match (effective_name or alias)
859    pub name: &'static str,
860    /// The field index
861    pub index: usize,
862    /// Whether this is an alias (vs primary name)
863    pub is_alias: bool,
864}
865
866/// Fast lookup from variant name to variant index.
867#[derive(Debug, Clone)]
868#[allow(clippy::large_enum_variant)] // SmallVec is intentionally inline
869pub enum VariantLookup {
870    /// For small enums: linear scan (most enums have ≤8 variants)
871    Small(SmallVec<(&'static str, usize), 8>),
872    /// For larger enums: sorted for binary search (range into buckets arena repurposed)
873    Sorted(Vec<(&'static str, usize)>),
874}
875
876// Threshold for switching from linear to prefix-based lookup
877const LOOKUP_THRESHOLD: usize = 8;
878
879/// Compute prefix from field name (first N bytes as little-endian u64).
880/// Matches JIT's compute_field_prefix.
881#[inline]
882fn compute_prefix(name: &str, prefix_len: usize) -> u64 {
883    let bytes = name.as_bytes();
884    let actual_len = bytes.len().min(prefix_len);
885    let mut prefix: u64 = 0;
886    for (i, &byte) in bytes.iter().take(actual_len).enumerate() {
887        prefix |= (byte as u64) << (i * 8);
888    }
889    prefix
890}
891
892impl FieldLookup {
893    /// Find a field index by name.
894    #[inline]
895    pub fn find(&self, name: &str, core: &TypePlanCore) -> Option<usize> {
896        match self {
897            FieldLookup::Small(entries) => entries.iter().find(|e| e.name == name).map(|e| e.index),
898            FieldLookup::PrefixBuckets {
899                prefix_len,
900                entries,
901                buckets,
902            } => {
903                let prefix = compute_prefix(name, *prefix_len);
904
905                // Get the bucket slice from arena
906                let bucket_slice = core.buckets.get_slice(*buckets);
907                let bucket_idx = bucket_slice
908                    .binary_search_by_key(&prefix, |(p, _, _)| *p)
909                    .ok()?;
910                let (_, start, count) = bucket_slice[bucket_idx];
911
912                // Get entries slice from arena
913                let all_entries = core.field_entries.get_slice(*entries);
914                let bucket_entries = &all_entries[start as usize..(start + count) as usize];
915                bucket_entries
916                    .iter()
917                    .find(|e| e.name == name)
918                    .map(|e| e.index)
919            }
920        }
921    }
922
923    /// Find a field index by name (standalone version for Small lookup only).
924    /// For use in tests and contexts without TypePlanCore access.
925    #[inline]
926    pub fn find_small(&self, name: &str) -> Option<usize> {
927        match self {
928            FieldLookup::Small(entries) => entries.iter().find(|e| e.name == name).map(|e| e.index),
929            FieldLookup::PrefixBuckets { .. } => {
930                panic!("find_small called on PrefixBuckets - use find() with TypePlanCore")
931            }
932        }
933    }
934
935    /// Check if empty.
936    #[inline]
937    pub fn is_empty(&self) -> bool {
938        match self {
939            FieldLookup::Small(entries) => entries.is_empty(),
940            FieldLookup::PrefixBuckets { entries, .. } => entries.is_empty(),
941        }
942    }
943}
944
945impl VariantLookup {
946    /// Find a variant index by name.
947    #[inline]
948    pub fn find(&self, name: &str) -> Option<usize> {
949        match self {
950            VariantLookup::Small(entries) => {
951                entries.iter().find(|(n, _)| *n == name).map(|(_, i)| *i)
952            }
953            VariantLookup::Sorted(entries) => entries
954                .binary_search_by_key(&name, |(n, _)| *n)
955                .ok()
956                .map(|i| entries[i].1),
957        }
958    }
959}
960
961/// Builder context for TypePlan construction.
962struct TypePlanBuilder {
963    /// Arena for nodes
964    nodes: Arena<TypePlanNode>,
965    /// Arena for field plans
966    fields: Arena<FieldPlan>,
967    /// Arena for variant metadata
968    variants: Arena<VariantPlanMeta>,
969    /// Arena for validators
970    validators: Arena<PrecomputedValidator>,
971    /// Arena for field lookup entries
972    field_entries: Arena<FieldLookupEntry>,
973    /// Arena for bucket tuples
974    buckets: Arena<(u64, u32, u32)>,
975    /// Types we're currently building (for cycle detection).
976    /// Added when we START building a node.
977    building: hashbrown::HashSet<ConstTypeId>,
978    /// Finished nodes, keyed by TypeId.
979    /// Added when we FINISH building a node.
980    finished: HashMap<ConstTypeId, NodeId>,
981}
982
983impl TypePlanBuilder {
984    fn new() -> Self {
985        Self {
986            nodes: Arena::new(),
987            fields: Arena::new(),
988            variants: Arena::new(),
989            validators: Arena::new(),
990            field_entries: Arena::new(),
991            buckets: Arena::new(),
992            building: hashbrown::HashSet::new(),
993            finished: HashMap::new(),
994        }
995    }
996
997    /// Finalize the builder into a TypePlanCore.
998    fn finish(self, root: NodeId) -> TypePlanCore {
999        let mut node_lookup: Vec<_> = self.finished.into_iter().collect();
1000        node_lookup.sort_by_key(|(id, _)| *id);
1001
1002        TypePlanCore {
1003            nodes: self.nodes,
1004            fields: self.fields,
1005            variants: self.variants,
1006            validators: self.validators,
1007            field_entries: self.field_entries,
1008            buckets: self.buckets,
1009            node_lookup,
1010            root,
1011        }
1012    }
1013
1014    /// Build a node for a shape, returning its index.
1015    /// Uses the shape's own proxy if present (container-level proxy).
1016    fn build_node(&mut self, shape: &'static Shape) -> Result<NodeId, AllocError> {
1017        // No field-level proxy when building directly - container proxy will be detected
1018        // inside build_node_with_proxy from the shape itself
1019        self.build_node_with_proxy(shape, None)
1020    }
1021
1022    /// Build a node for a shape with an optional explicit field-level proxy.
1023    /// Used for field-level proxies where the proxy is on the field, not the type.
1024    fn build_node_with_proxy(
1025        &mut self,
1026        shape: &'static Shape,
1027        field_proxies: Option<FieldProxies>,
1028    ) -> Result<NodeId, AllocError> {
1029        let type_id = shape.id;
1030
1031        // Check if we're currently building this type (cycle detected)
1032        if self.building.contains(&type_id) {
1033            // Create a BackRef node with just the TypeId - resolved later via lookup
1034            let backref_node = TypePlanNode {
1035                shape,
1036                kind: TypePlanNodeKind::BackRef(type_id),
1037                strategy: DeserStrategy::BackRef {
1038                    target_type_id: type_id,
1039                },
1040                has_default: shape.is(Characteristic::Default),
1041                proxies: ProxyNodes::default(), // BackRefs resolve to target, proxies come from there
1042            };
1043            let idx = self.nodes.alloc(backref_node);
1044            return Ok(idx);
1045        }
1046
1047        // Mark this type as being built (for cycle detection)
1048        self.building.insert(type_id);
1049
1050        // Build proxy nodes for ALL proxies (generic + all format-specific)
1051        let (proxies, has_container_proxy, has_field_proxy) =
1052            self.build_all_proxy_nodes(shape, field_proxies.as_ref())?;
1053
1054        let (kind, children) = self.build_kind(shape)?;
1055
1056        let strategy = self.compute_strategy(
1057            shape,
1058            &kind,
1059            has_container_proxy,
1060            has_field_proxy,
1061            &children,
1062        )?;
1063
1064        // Now allocate the node with final values (no mutation needed!)
1065        let node = TypePlanNode {
1066            shape,
1067            kind,
1068            strategy,
1069            has_default: shape.is(Characteristic::Default),
1070            proxies,
1071        };
1072        let idx = self.nodes.alloc(node);
1073
1074        // Done building - move from building set to finished map
1075        self.building.remove(&type_id);
1076        self.finished.insert(type_id, idx);
1077
1078        Ok(idx)
1079    }
1080
1081    /// Build TypePlan nodes for all proxies on a shape/field.
1082    ///
1083    /// Returns (ProxyNodes, has_container_proxy, has_field_proxy).
1084    fn build_all_proxy_nodes(
1085        &mut self,
1086        shape: &'static Shape,
1087        field_proxies: Option<&FieldProxies>,
1088    ) -> Result<(ProxyNodes, bool, bool), AllocError> {
1089        let mut proxies = ProxyNodes::default();
1090
1091        // Field-level proxies take precedence over container-level
1092        if let Some(fp) = field_proxies {
1093            // Build nodes for field-level proxies
1094            if let Some(generic_proxy) = fp.generic {
1095                proxies.generic = Some(self.build_node(generic_proxy.shape)?);
1096            }
1097            for &(format, proxy_def) in fp.format_specific.iter() {
1098                let node = self.build_node(proxy_def.shape)?;
1099                proxies.format_specific.push((format, node));
1100            }
1101            let has_field_proxy = proxies.has_any();
1102            return Ok((proxies, false, has_field_proxy));
1103        }
1104
1105        // Container-level proxies (from the shape itself)
1106        // Build generic proxy node
1107        if let Some(generic_proxy) = shape.proxy {
1108            proxies.generic = Some(self.build_node(generic_proxy.shape)?);
1109        }
1110
1111        // Build format-specific proxy nodes
1112        for format_proxy in shape.format_proxies.iter() {
1113            let node = self.build_node(format_proxy.proxy.shape)?;
1114            proxies.format_specific.push((format_proxy.format, node));
1115        }
1116
1117        let has_container_proxy = proxies.has_any();
1118        Ok((proxies, has_container_proxy, false))
1119    }
1120
1121    /// Compute the deserialization strategy with all data needed to execute it.
1122    fn compute_strategy(
1123        &self,
1124        shape: &'static Shape,
1125        kind: &TypePlanNodeKind,
1126        has_container_proxy: bool,
1127        has_field_proxy: bool,
1128        children: &[NodeId],
1129    ) -> Result<DeserStrategy, AllocError> {
1130        let nth_child = |n: usize| -> NodeId { children[n] };
1131        let first_child = || children[0];
1132
1133        // Priority 1: Field-level proxy (field has proxy, type doesn't)
1134        if has_field_proxy {
1135            return Ok(DeserStrategy::FieldProxy);
1136        }
1137
1138        // Priority 2: Container-level proxy (type itself has proxy)
1139        if has_container_proxy {
1140            return Ok(DeserStrategy::ContainerProxy);
1141        }
1142
1143        // Priority 3: Smart pointers (Box, Arc, Rc)
1144        if matches!(kind, TypePlanNodeKind::Pointer) {
1145            return Ok(DeserStrategy::Pointer {
1146                pointee_node: first_child(),
1147            });
1148        }
1149
1150        // Priority 4: Metadata containers (like Spanned<T>, Documented<T>)
1151        if shape.is_metadata_container() {
1152            return Ok(DeserStrategy::MetadataContainer);
1153        }
1154
1155        // Priority 5: Types with .inner and try_from (like NonZero<T>)
1156        if shape.inner.is_some()
1157            && shape.vtable.has_try_from()
1158            && !matches!(
1159                &shape.def,
1160                Def::List(_) | Def::Map(_) | Def::Set(_) | Def::Array(_)
1161            )
1162        {
1163            return Ok(DeserStrategy::TransparentConvert {
1164                inner_node: first_child(),
1165            });
1166        }
1167
1168        // Priority 6: Transparent wrappers with try_from
1169        if matches!(kind, TypePlanNodeKind::Transparent) && shape.vtable.has_try_from() {
1170            return Ok(DeserStrategy::TransparentConvert {
1171                inner_node: first_child(),
1172            });
1173        }
1174
1175        // Priority 7: Scalars with FromStr
1176        if matches!(&shape.def, Def::Scalar) && shape.vtable.has_parse() {
1177            return Ok(DeserStrategy::Scalar {
1178                scalar_type: shape.scalar_type(),
1179                is_from_str: shape.vtable.has_parse(),
1180            });
1181        }
1182
1183        // Priority 8: Match on the kind
1184        Ok(match kind {
1185            TypePlanNodeKind::Scalar => {
1186                // Empty tuple has def: Scalar but ty: Struct(Tuple)
1187                if let Type::User(UserType::Struct(struct_def)) = &shape.ty {
1188                    use facet_core::StructKind;
1189                    if matches!(struct_def.kind, StructKind::Tuple | StructKind::TupleStruct) {
1190                        let field_count = struct_def.fields.len();
1191                        return Ok(DeserStrategy::Tuple {
1192                            field_count,
1193                            is_single_field_transparent: field_count == 1 && shape.is_transparent(),
1194                        });
1195                    }
1196                }
1197                DeserStrategy::Scalar {
1198                    scalar_type: shape.scalar_type(),
1199                    is_from_str: shape.vtable.has_parse(),
1200                }
1201            }
1202            TypePlanNodeKind::Struct(struct_plan) => {
1203                use facet_core::StructKind;
1204                match struct_plan.struct_def.kind {
1205                    StructKind::Tuple | StructKind::TupleStruct => {
1206                        let field_count = struct_plan.struct_def.fields.len();
1207                        DeserStrategy::Tuple {
1208                            field_count,
1209                            is_single_field_transparent: field_count == 1 && shape.is_transparent(),
1210                        }
1211                    }
1212                    StructKind::Struct | StructKind::Unit => DeserStrategy::Struct,
1213                }
1214            }
1215            TypePlanNodeKind::Enum(_) => DeserStrategy::Enum,
1216            TypePlanNodeKind::Option => DeserStrategy::Option {
1217                some_node: first_child(),
1218            },
1219            TypePlanNodeKind::Result => DeserStrategy::Result {
1220                ok_node: nth_child(0),
1221                err_node: nth_child(1),
1222            },
1223            TypePlanNodeKind::List | TypePlanNodeKind::Slice => {
1224                // Check if this is Vec<u8> for optimized byte sequence handling
1225                let is_byte_vec = *shape == *<alloc::vec::Vec<u8> as facet_core::Facet>::SHAPE;
1226                DeserStrategy::List {
1227                    item_node: first_child(),
1228                    is_byte_vec,
1229                }
1230            }
1231            TypePlanNodeKind::Map => DeserStrategy::Map {
1232                key_node: nth_child(0),
1233                value_node: nth_child(1),
1234            },
1235            TypePlanNodeKind::Set => DeserStrategy::Set {
1236                item_node: first_child(),
1237            },
1238            TypePlanNodeKind::Array { len } => DeserStrategy::Array {
1239                len: *len,
1240                item_node: first_child(),
1241            },
1242            TypePlanNodeKind::DynamicValue => DeserStrategy::DynamicValue,
1243            TypePlanNodeKind::Pointer => DeserStrategy::Pointer {
1244                pointee_node: first_child(),
1245            },
1246            TypePlanNodeKind::OpaquePointer => DeserStrategy::OpaquePointer,
1247            TypePlanNodeKind::Opaque => DeserStrategy::Opaque,
1248            TypePlanNodeKind::Transparent => {
1249                // Transparent wrapper without try_from - unsupported
1250                return Err(AllocError {
1251                    shape,
1252                    operation: "transparent wrapper requires try_from for deserialization",
1253                });
1254            }
1255            TypePlanNodeKind::BackRef(type_id) => DeserStrategy::BackRef {
1256                target_type_id: *type_id,
1257            },
1258        })
1259    }
1260
1261    /// Build the TypePlanNodeKind for a shape and return child node indices for compute_strategy.
1262    fn build_kind(
1263        &mut self,
1264        shape: &'static Shape,
1265    ) -> Result<(TypePlanNodeKind, Vec<NodeId>), AllocError> {
1266        let mut children = Vec::new();
1267
1268        // Check shape.def first - this tells us the semantic meaning of the type
1269        let kind = match &shape.def {
1270            Def::Scalar => {
1271                // For scalar types with shape.inner (like NonZero<T>), build a child node
1272                // for the inner type. This enables proper TypePlan navigation when
1273                // begin_inner() is called for transparent wrapper deserialization.
1274                if let Some(inner_shape) = shape.inner {
1275                    children.push(self.build_node(inner_shape)?);
1276                }
1277                TypePlanNodeKind::Scalar
1278            }
1279
1280            Def::Option(opt_def) => {
1281                children.push(self.build_node(opt_def.t())?);
1282                TypePlanNodeKind::Option
1283            }
1284
1285            Def::Result(res_def) => {
1286                children.push(self.build_node(res_def.t())?);
1287                children.push(self.build_node(res_def.e())?);
1288                TypePlanNodeKind::Result
1289            }
1290
1291            Def::List(list_def) => {
1292                children.push(self.build_node(list_def.t())?);
1293                TypePlanNodeKind::List
1294            }
1295
1296            Def::Map(map_def) => {
1297                children.push(self.build_node(map_def.k())?);
1298                children.push(self.build_node(map_def.v())?);
1299                TypePlanNodeKind::Map
1300            }
1301
1302            Def::Set(set_def) => {
1303                children.push(self.build_node(set_def.t())?);
1304                TypePlanNodeKind::Set
1305            }
1306
1307            Def::Array(arr_def) => {
1308                children.push(self.build_node(arr_def.t())?);
1309                TypePlanNodeKind::Array { len: arr_def.n }
1310            }
1311
1312            Def::Pointer(ptr_def) => {
1313                if let Some(pointee) = ptr_def.pointee() {
1314                    children.push(self.build_node(pointee)?);
1315                    TypePlanNodeKind::Pointer
1316                } else {
1317                    // Opaque pointer - no pointee shape available
1318                    TypePlanNodeKind::OpaquePointer
1319                }
1320            }
1321
1322            Def::DynamicValue(_) => TypePlanNodeKind::DynamicValue,
1323
1324            _ => {
1325                // Check Type for struct/enum/slice - these have Def::Undefined but meaningful ty
1326                match &shape.ty {
1327                    Type::User(UserType::Struct(struct_type)) => {
1328                        let struct_plan = self.build_struct_plan(shape, struct_type)?;
1329                        // Struct fields store their NodeIds in FieldPlan, no children needed
1330                        return Ok((TypePlanNodeKind::Struct(struct_plan), Vec::new()));
1331                    }
1332                    Type::User(UserType::Enum(enum_type)) => {
1333                        // Enum variants store their NodeIds in VariantPlanMeta, no children needed
1334                        TypePlanNodeKind::Enum(self.build_enum_plan(enum_type)?)
1335                    }
1336                    // Handle slices like lists - they have an element type
1337                    Type::Sequence(SequenceType::Slice(slice_type)) => {
1338                        children.push(self.build_node(slice_type.t)?);
1339                        // Use Slice kind so we can distinguish from List if needed
1340                        TypePlanNodeKind::Slice
1341                    }
1342                    // Opaque types have Def::Undefined AND ty that doesn't match above
1343                    Type::User(UserType::Opaque) | Type::Undefined => TypePlanNodeKind::Opaque,
1344                    _ => {
1345                        // Check for transparent wrappers (newtypes) as fallback
1346                        if let Some(inner) = shape.inner {
1347                            children.push(self.build_node(inner)?);
1348                            TypePlanNodeKind::Transparent
1349                        } else {
1350                            return Err(AllocError {
1351                                shape,
1352                                operation: "unsupported type for deserialization",
1353                            });
1354                        }
1355                    }
1356                }
1357            }
1358        };
1359        Ok((kind, children))
1360    }
1361
1362    /// Build a StructPlan with all field plans.
1363    fn build_struct_plan(
1364        &mut self,
1365        shape: &'static Shape,
1366        struct_def: &'static StructType,
1367    ) -> Result<StructPlan, AllocError> {
1368        let mut field_plans = Vec::with_capacity(struct_def.fields.len());
1369
1370        // Check if the container struct has #[facet(default)]
1371        let container_has_default = shape.is(Characteristic::Default);
1372
1373        for (index, field) in struct_def.fields.iter().enumerate() {
1374            // Build the type plan node for this field first
1375            let field_proxies = FieldProxies::from_field(field);
1376            let child_node = self.build_node_with_proxy(field.shape(), field_proxies)?;
1377
1378            // Build validators and fill rule
1379            let validators = self.extract_validators(field);
1380            let fill_rule = Self::determine_fill_rule(field, container_has_default);
1381
1382            // Create unified field plan
1383            field_plans
1384                .push(self.create_field_plan(index, field, child_node, fill_rule, validators));
1385        }
1386
1387        // Allocate fields into arena
1388        let has_flatten = field_plans.iter().any(|f| f.is_flattened);
1389        let fields = self.fields.alloc_extend(field_plans.iter().cloned());
1390
1391        // Build field lookup
1392        let field_lookup = self.build_field_lookup(&field_plans);
1393
1394        // Precompute deny_unknown_fields from shape attributes (avoids runtime attribute scanning)
1395        let deny_unknown_fields = shape.has_deny_unknown_fields_attr();
1396
1397        Ok(StructPlan {
1398            struct_def,
1399            fields,
1400            field_lookup,
1401            has_flatten,
1402            deny_unknown_fields,
1403        })
1404    }
1405
1406    /// Create a FieldPlan from its components.
1407    fn create_field_plan(
1408        &mut self,
1409        index: usize,
1410        field: &'static Field,
1411        type_node: NodeId,
1412        fill_rule: FillRule,
1413        validators: ValidatorRange,
1414    ) -> FieldPlan {
1415        let name = field.name;
1416        let effective_name = field.effective_name();
1417        let alias = field.alias;
1418        let is_flattened = field.is_flattened();
1419
1420        FieldPlan {
1421            // Metadata for matching/lookup
1422            field,
1423            name,
1424            effective_name,
1425            alias,
1426            is_flattened,
1427            type_node,
1428            // Initialization/validation
1429            index,
1430            offset: field.offset,
1431            field_shape: field.shape(),
1432            fill_rule,
1433            validators,
1434        }
1435    }
1436
1437    /// Build a field lookup from field plans.
1438    fn build_field_lookup(&mut self, field_plans: &[FieldPlan]) -> FieldLookup {
1439        let mut entries: Vec<FieldLookupEntry> = Vec::with_capacity(field_plans.len() * 2);
1440
1441        for (index, field_plan) in field_plans.iter().enumerate() {
1442            // Add primary name
1443            entries.push(FieldLookupEntry {
1444                name: field_plan.effective_name,
1445                index,
1446                is_alias: false,
1447            });
1448
1449            // Add alias if present
1450            if let Some(alias) = field_plan.alias {
1451                entries.push(FieldLookupEntry {
1452                    name: alias,
1453                    index,
1454                    is_alias: true,
1455                });
1456            }
1457        }
1458
1459        self.build_field_lookup_from_entries(entries)
1460    }
1461
1462    /// Build lookup structure from entries.
1463    fn build_field_lookup_from_entries(&mut self, entries: Vec<FieldLookupEntry>) -> FieldLookup {
1464        let total_entries = entries.len();
1465        if total_entries <= LOOKUP_THRESHOLD {
1466            return FieldLookup::Small(entries.into_iter().collect());
1467        }
1468
1469        // Choose prefix length: 8 bytes if most keys are long, otherwise 4
1470        let long_key_count = entries.iter().filter(|e| e.name.len() >= 8).count();
1471        let prefix_len = if long_key_count > total_entries / 2 {
1472            8
1473        } else {
1474            4
1475        };
1476
1477        // Group entries by prefix
1478        let mut prefix_map: hashbrown::HashMap<u64, Vec<FieldLookupEntry>> =
1479            hashbrown::HashMap::new();
1480        for entry in entries {
1481            let prefix = compute_prefix(entry.name, prefix_len);
1482            prefix_map.entry(prefix).or_default().push(entry);
1483        }
1484
1485        // Build sorted bucket list and flattened entries
1486        let mut bucket_list: Vec<_> = prefix_map.into_iter().collect();
1487        bucket_list.sort_by_key(|(prefix, _)| *prefix);
1488
1489        let mut all_entries = Vec::with_capacity(total_entries);
1490        let mut bucket_data = Vec::with_capacity(bucket_list.len());
1491
1492        for (prefix, bucket_entries) in bucket_list {
1493            let start = all_entries.len() as u32;
1494            let count = bucket_entries.len() as u32;
1495            bucket_data.push((prefix, start, count));
1496            all_entries.extend(bucket_entries);
1497        }
1498
1499        // Allocate into arenas
1500        let entries_range = self.field_entries.alloc_extend(all_entries);
1501        let buckets_range = self.buckets.alloc_extend(bucket_data);
1502
1503        FieldLookup::PrefixBuckets {
1504            prefix_len,
1505            entries: entries_range,
1506            buckets: buckets_range,
1507        }
1508    }
1509
1510    /// Determine how to fill a field that wasn't set.
1511    fn determine_fill_rule(field: &'static Field, container_has_default: bool) -> FillRule {
1512        let field_shape = field.shape();
1513
1514        // Check for explicit default on the field (#[facet(default)] or #[facet(default = expr)])
1515        if let Some(default_source) = field.default_source() {
1516            let field_default = match default_source {
1517                DefaultSource::Custom(f) => FieldDefault::Custom(*f),
1518                DefaultSource::FromTrait => FieldDefault::FromTrait(field_shape),
1519            };
1520            return FillRule::Defaultable(field_default);
1521        }
1522
1523        // Option<T> without explicit default implicitly defaults to None
1524        let is_option = matches!(field_shape.def, Def::Option(_));
1525        if is_option && field_shape.is(Characteristic::Default) {
1526            return FillRule::Defaultable(FieldDefault::FromTrait(field_shape));
1527        }
1528
1529        // Skipped fields MUST have a default (they're never deserialized)
1530        if field.should_skip_deserializing() && field_shape.is(Characteristic::Default) {
1531            return FillRule::Defaultable(FieldDefault::FromTrait(field_shape));
1532        }
1533
1534        // Empty structs/tuples (like `()`) are trivially defaultable
1535        if let Type::User(UserType::Struct(struct_type)) = field_shape.ty
1536            && struct_type.fields.is_empty()
1537            && field_shape.is(Characteristic::Default)
1538        {
1539            return FillRule::Defaultable(FieldDefault::FromTrait(field_shape));
1540        }
1541
1542        // If container has #[facet(default)] and the field's type implements Default,
1543        // use the type's Default impl
1544        if container_has_default && field_shape.is(Characteristic::Default) {
1545            return FillRule::Defaultable(FieldDefault::FromTrait(field_shape));
1546        }
1547
1548        // Field is required - must be set during deserialization
1549        FillRule::Required
1550    }
1551
1552    /// Extract validators from field attributes.
1553    fn extract_validators(&mut self, field: &'static Field) -> ValidatorRange {
1554        let mut validators = Vec::new();
1555        let field_shape = field.shape();
1556        // Precompute scalar type once - used by validators that need it
1557        let scalar_type = field_shape.scalar_type();
1558
1559        for attr in field.attributes.iter() {
1560            if attr.ns != Some("validate") {
1561                continue;
1562            }
1563
1564            let kind = match attr.key {
1565                "custom" => {
1566                    // SAFETY: validate::custom attribute stores a ValidatorFn
1567                    let validator_fn = unsafe { *attr.data.ptr().get::<ValidatorFn>() };
1568                    ValidatorKind::Custom(validator_fn)
1569                }
1570                "min" => {
1571                    let limit = *attr
1572                        .get_as::<i64>()
1573                        .expect("validate::min attribute must contain i64");
1574                    let scalar_type =
1575                        scalar_type.expect("validate::min requires numeric field type");
1576                    ValidatorKind::Min { limit, scalar_type }
1577                }
1578                "max" => {
1579                    let limit = *attr
1580                        .get_as::<i64>()
1581                        .expect("validate::max attribute must contain i64");
1582                    let scalar_type =
1583                        scalar_type.expect("validate::max requires numeric field type");
1584                    ValidatorKind::Max { limit, scalar_type }
1585                }
1586                "min_length" => {
1587                    let limit = *attr
1588                        .get_as::<usize>()
1589                        .expect("validate::min_length attribute must contain usize");
1590                    let scalar_type =
1591                        scalar_type.expect("validate::min_length requires string field type");
1592                    ValidatorKind::MinLength { limit, scalar_type }
1593                }
1594                "max_length" => {
1595                    let limit = *attr
1596                        .get_as::<usize>()
1597                        .expect("validate::max_length attribute must contain usize");
1598                    let scalar_type =
1599                        scalar_type.expect("validate::max_length requires string field type");
1600                    ValidatorKind::MaxLength { limit, scalar_type }
1601                }
1602                "email" => {
1603                    let scalar_type =
1604                        scalar_type.expect("validate::email requires string field type");
1605                    ValidatorKind::Email { scalar_type }
1606                }
1607                "url" => {
1608                    let scalar_type =
1609                        scalar_type.expect("validate::url requires string field type");
1610                    ValidatorKind::Url { scalar_type }
1611                }
1612                "regex" => {
1613                    let pattern = *attr
1614                        .get_as::<&'static str>()
1615                        .expect("validate::regex attribute must contain &'static str");
1616                    let scalar_type =
1617                        scalar_type.expect("validate::regex requires string field type");
1618                    ValidatorKind::Regex {
1619                        pattern,
1620                        scalar_type,
1621                    }
1622                }
1623                "contains" => {
1624                    let needle = *attr
1625                        .get_as::<&'static str>()
1626                        .expect("validate::contains attribute must contain &'static str");
1627                    let scalar_type =
1628                        scalar_type.expect("validate::contains requires string field type");
1629                    ValidatorKind::Contains {
1630                        needle,
1631                        scalar_type,
1632                    }
1633                }
1634                _ => continue, // Unknown validator, skip
1635            };
1636
1637            validators.push(PrecomputedValidator { kind });
1638        }
1639
1640        self.validators.alloc_extend(validators)
1641    }
1642
1643    /// Build an EnumPlan with all field plans for each variant.
1644    fn build_enum_plan(&mut self, enum_def: &'static EnumType) -> Result<EnumPlan, AllocError> {
1645        let mut variant_metas = Vec::with_capacity(enum_def.variants.len());
1646
1647        for variant in enum_def.variants.iter() {
1648            let mut field_plans = Vec::with_capacity(variant.data.fields.len());
1649
1650            for (index, field) in variant.data.fields.iter().enumerate() {
1651                // Build the type plan node for this field
1652                let field_proxies = FieldProxies::from_field(field);
1653                let child_node = self.build_node_with_proxy(field.shape(), field_proxies)?;
1654
1655                // Build validators and fill rule (enums don't have container-level default)
1656                let validators = self.extract_validators(field);
1657                let fill_rule = Self::determine_fill_rule(field, false);
1658
1659                // Create unified field plan
1660                field_plans
1661                    .push(self.create_field_plan(index, field, child_node, fill_rule, validators));
1662            }
1663
1664            let has_flatten = field_plans.iter().any(|f| f.is_flattened);
1665            let fields = self.fields.alloc_extend(field_plans.iter().cloned());
1666            let field_lookup = self.build_field_lookup(&field_plans);
1667
1668            variant_metas.push(VariantPlanMeta {
1669                variant,
1670                name: variant.effective_name(),
1671                fields,
1672                field_lookup,
1673                has_flatten,
1674            });
1675        }
1676
1677        let variants = self.variants.alloc_extend(variant_metas.iter().cloned());
1678        let variant_lookup = self.build_variant_lookup(&variant_metas);
1679        let num_variants = variant_metas.len();
1680
1681        // Find the index of the #[facet(other)] variant, if any
1682        let other_variant_idx = variant_metas.iter().position(|v| v.variant.is_other());
1683
1684        Ok(EnumPlan {
1685            enum_def,
1686            variants,
1687            variant_lookup,
1688            num_variants,
1689            other_variant_idx,
1690        })
1691    }
1692
1693    /// Build a variant lookup from variant metadata.
1694    ///
1695    /// Note: `#[facet(other)]` variants are excluded from the lookup because they
1696    /// should only be used as a fallback when no other variant matches. Including
1697    /// them would cause serialized `#[facet(other)]` values to deserialize via
1698    /// the normal path instead of the fallback path.
1699    fn build_variant_lookup(&self, variants: &[VariantPlanMeta]) -> VariantLookup {
1700        let entries: Vec<_> = variants
1701            .iter()
1702            .enumerate()
1703            .filter(|(_, v)| !v.variant.is_other())
1704            .map(|(i, v)| (v.name, i))
1705            .collect();
1706
1707        if entries.len() <= LOOKUP_THRESHOLD {
1708            VariantLookup::Small(entries.into_iter().collect())
1709        } else {
1710            let mut sorted = entries;
1711            sorted.sort_by_key(|(name, _)| *name);
1712            VariantLookup::Sorted(sorted)
1713        }
1714    }
1715}
1716
1717impl<'facet, T: facet_core::Facet<'facet> + ?Sized> TypePlan<T> {
1718    /// Build a TypePlan for type `T`.
1719    ///
1720    /// The type parameter provides compile-time safety: you cannot accidentally
1721    /// pass a `TypePlan<Foo>` where `TypePlan<Bar>` is expected.
1722    ///
1723    /// Note: TypePlan can be built for any `Facet<'_>` type because the `SHAPE`
1724    /// is always `'static`. The lifetime parameter on `Facet` only affects the
1725    /// runtime deserialized values, not the type metadata.
1726    ///
1727    /// # Example
1728    ///
1729    /// ```ignore
1730    /// use facet_reflect::TypePlan;
1731    ///
1732    /// let plan = TypePlan::<MyStruct>::build()?;
1733    /// ```
1734    pub fn build() -> Result<Self, AllocError> {
1735        // SAFETY: T::SHAPE comes from Facet metadata for a real type T.
1736        let core = unsafe { TypePlanCore::from_shape(T::SHAPE)? };
1737
1738        Ok(TypePlan {
1739            core,
1740            _marker: core::marker::PhantomData,
1741        })
1742    }
1743
1744    /// Build a TypePlan with format-specific proxy resolution.
1745    ///
1746    /// **Deprecated**: Format namespace is no longer needed at build time.
1747    /// TypePlan now stores proxy nodes for all formats, and the format-specific
1748    /// proxy is selected at runtime during deserialization.
1749    ///
1750    /// This method is kept for API compatibility but is equivalent to `build()`.
1751    #[deprecated(
1752        since = "0.44.0",
1753        note = "format namespace no longer needed at build time; use build() instead"
1754    )]
1755    pub fn build_for_format(_format_namespace: Option<&'static str>) -> Result<Self, AllocError> {
1756        Self::build()
1757    }
1758
1759    /// Get a reference to the internal core.
1760    #[inline]
1761    pub fn core(&self) -> Arc<TypePlanCore> {
1762        self.core.clone()
1763    }
1764
1765    /// Get the root node.
1766    #[inline]
1767    pub fn root(&self) -> &TypePlanNode {
1768        self.core.root()
1769    }
1770}
1771
1772impl TypePlanCore {
1773    /// Build a TypePlanCore directly from a shape, with process-global caching.
1774    ///
1775    /// Under `std`, one plan is cached per unique shape (`&'static Shape`) for
1776    /// the lifetime of the process. In `no_std`, this builds a fresh plan each call.
1777    ///
1778    /// # Safety
1779    ///
1780    /// The caller must ensure that the shape is valid and corresponds to a real type.
1781    /// Using an incorrect or maliciously crafted shape can lead to undefined behavior
1782    /// when materializing values.
1783    pub unsafe fn from_shape(shape: &'static Shape) -> Result<Arc<Self>, AllocError> {
1784        #[cfg(feature = "std")]
1785        {
1786            let mut guard = type_plan_cache()
1787                .lock()
1788                .unwrap_or_else(|poison| poison.into_inner());
1789
1790            if let Some(plan) = guard.get(&shape) {
1791                return Ok(Arc::clone(plan));
1792            }
1793
1794            // SAFETY: caller guarantees the shape is valid.
1795            let plan = unsafe { Self::build_uncached(shape)? };
1796            guard.insert(shape, Arc::clone(&plan));
1797            Ok(plan)
1798        }
1799
1800        #[cfg(not(feature = "std"))]
1801        {
1802            // SAFETY: caller guarantees the shape is valid.
1803            unsafe { Self::build_uncached(shape) }
1804        }
1805    }
1806
1807    /// Build a TypePlanCore from a shape without touching the global cache.
1808    ///
1809    /// # Safety
1810    ///
1811    /// Same safety contract as [`Self::from_shape`].
1812    unsafe fn build_uncached(shape: &'static Shape) -> Result<Arc<Self>, AllocError> {
1813        let mut builder = TypePlanBuilder::new();
1814        let root = builder.build_node(shape)?;
1815        Ok(Arc::new(builder.finish(root)))
1816    }
1817
1818    /// Get the root node.
1819    #[inline]
1820    pub fn root(&self) -> &TypePlanNode {
1821        self.node(self.root)
1822    }
1823
1824    /// Get the root node index.
1825    #[inline]
1826    pub fn root_id(&self) -> NodeId {
1827        self.root
1828    }
1829
1830    /// Get a node by its index.
1831    #[inline]
1832    pub fn node(&self, idx: NodeId) -> &TypePlanNode {
1833        self.nodes.get(idx)
1834    }
1835
1836    /// Get a field by its index.
1837    #[inline]
1838    pub fn field(&self, idx: Idx<FieldPlan>) -> &FieldPlan {
1839        self.fields.get(idx)
1840    }
1841
1842    /// Get a slice of fields from a range.
1843    #[inline]
1844    pub fn fields(&self, range: FieldRange) -> &[FieldPlan] {
1845        self.fields.get_slice(range)
1846    }
1847
1848    /// Get a variant by its index.
1849    #[inline]
1850    pub fn variant(&self, idx: Idx<VariantPlanMeta>) -> &VariantPlanMeta {
1851        self.variants.get(idx)
1852    }
1853
1854    /// Get a slice of variants from a range.
1855    #[inline]
1856    pub fn variants(&self, range: VariantRange) -> &[VariantPlanMeta] {
1857        self.variants.get_slice(range)
1858    }
1859
1860    /// Get a slice of validators from a range.
1861    #[inline]
1862    pub fn validators(&self, range: ValidatorRange) -> &[PrecomputedValidator] {
1863        self.validators.get_slice(range)
1864    }
1865
1866    /// Look up a node by TypeId using binary search on the sorted lookup table.
1867    #[inline]
1868    fn lookup_node(&self, type_id: &ConstTypeId) -> Option<NodeId> {
1869        let idx = self
1870            .node_lookup
1871            .binary_search_by_key(type_id, |(id, _)| *id)
1872            .ok()?;
1873        Some(self.node_lookup[idx].1)
1874    }
1875
1876    // Navigation helpers
1877
1878    /// Get the child node for a struct field by index.
1879    /// Follows BackRef nodes for recursive types.
1880    #[inline]
1881    pub fn struct_field_node(&self, parent: &TypePlanNode, idx: usize) -> Option<&TypePlanNode> {
1882        let resolved = self.resolve_backref(parent);
1883        let struct_plan = match &resolved.kind {
1884            TypePlanNodeKind::Struct(p) => p,
1885            _ => return None,
1886        };
1887        let fields = self.fields(struct_plan.fields);
1888        Some(self.node(fields.get(idx)?.type_node))
1889    }
1890
1891    /// Get the child node for an enum variant's field.
1892    /// Follows BackRef nodes for recursive types.
1893    #[inline]
1894    pub fn enum_variant_field_node(
1895        &self,
1896        parent: &TypePlanNode,
1897        variant_idx: usize,
1898        field_idx: usize,
1899    ) -> Option<&TypePlanNode> {
1900        let resolved = self.resolve_backref(parent);
1901        let enum_plan = match &resolved.kind {
1902            TypePlanNodeKind::Enum(p) => p,
1903            _ => return None,
1904        };
1905        let variants = self.variants(enum_plan.variants);
1906        let variant = variants.get(variant_idx)?;
1907        let fields = self.fields(variant.fields);
1908        Some(self.node(fields.get(field_idx)?.type_node))
1909    }
1910
1911    /// Get the child node for list/array items.
1912    #[inline]
1913    pub fn list_item_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1914        match &parent.strategy {
1915            DeserStrategy::List { item_node, .. } | DeserStrategy::Array { item_node, .. } => {
1916                Some(self.node(*item_node))
1917            }
1918            DeserStrategy::BackRef { target_type_id } => {
1919                let target = self.lookup_node(target_type_id)?;
1920                self.list_item_node(self.node(target))
1921            }
1922            _ => None,
1923        }
1924    }
1925
1926    /// Get the child node for set items.
1927    #[inline]
1928    pub fn set_item_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1929        match &parent.strategy {
1930            DeserStrategy::Set { item_node } => Some(self.node(*item_node)),
1931            DeserStrategy::BackRef { target_type_id } => {
1932                let target = self.lookup_node(target_type_id)?;
1933                self.set_item_node(self.node(target))
1934            }
1935            _ => None,
1936        }
1937    }
1938
1939    /// Get the child node for map keys.
1940    #[inline]
1941    pub fn map_key_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1942        match &parent.strategy {
1943            DeserStrategy::Map { key_node, .. } => Some(self.node(*key_node)),
1944            DeserStrategy::BackRef { target_type_id } => {
1945                let target = self.lookup_node(target_type_id)?;
1946                self.map_key_node(self.node(target))
1947            }
1948            _ => None,
1949        }
1950    }
1951
1952    /// Get the child node for map values.
1953    #[inline]
1954    pub fn map_value_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1955        match &parent.strategy {
1956            DeserStrategy::Map { value_node, .. } => Some(self.node(*value_node)),
1957            DeserStrategy::BackRef { target_type_id } => {
1958                let target = self.lookup_node(target_type_id)?;
1959                self.map_value_node(self.node(target))
1960            }
1961            _ => None,
1962        }
1963    }
1964
1965    /// Get the child node for Option inner type.
1966    #[inline]
1967    pub fn option_inner_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1968        match &parent.strategy {
1969            DeserStrategy::Option { some_node } => Some(self.node(*some_node)),
1970            DeserStrategy::BackRef { target_type_id } => {
1971                let target = self.lookup_node(target_type_id)?;
1972                self.option_inner_node(self.node(target))
1973            }
1974            _ => None,
1975        }
1976    }
1977
1978    /// Get the child node for Result Ok type.
1979    #[inline]
1980    pub fn result_ok_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1981        match &parent.strategy {
1982            DeserStrategy::Result { ok_node, .. } => Some(self.node(*ok_node)),
1983            DeserStrategy::BackRef { target_type_id } => {
1984                let target = self.lookup_node(target_type_id)?;
1985                self.result_ok_node(self.node(target))
1986            }
1987            _ => None,
1988        }
1989    }
1990
1991    /// Get the child node for Result Err type.
1992    #[inline]
1993    pub fn result_err_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1994        match &parent.strategy {
1995            DeserStrategy::Result { err_node, .. } => Some(self.node(*err_node)),
1996            DeserStrategy::BackRef { target_type_id } => {
1997                let target = self.lookup_node(target_type_id)?;
1998                self.result_err_node(self.node(target))
1999            }
2000            _ => None,
2001        }
2002    }
2003
2004    /// Get the child node for pointer pointee.
2005    #[inline]
2006    pub fn pointer_pointee_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
2007        match &parent.strategy {
2008            DeserStrategy::Pointer { pointee_node } => Some(self.node(*pointee_node)),
2009            DeserStrategy::BackRef { target_type_id } => {
2010                let target = self.lookup_node(target_type_id)?;
2011                self.pointer_pointee_node(self.node(target))
2012            }
2013            _ => None,
2014        }
2015    }
2016
2017    /// Get the child node for shape.inner navigation (used by begin_inner).
2018    #[inline]
2019    pub fn inner_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
2020        if parent.shape.inner.is_some() {
2021            match &parent.strategy {
2022                DeserStrategy::TransparentConvert { inner_node } => Some(self.node(*inner_node)),
2023                _ => None,
2024            }
2025        } else {
2026            None
2027        }
2028    }
2029
2030    /// Resolve a BackRef to get the actual node it points to.
2031    #[inline]
2032    pub fn resolve_backref<'a>(&'a self, node: &'a TypePlanNode) -> &'a TypePlanNode {
2033        match &node.kind {
2034            TypePlanNodeKind::BackRef(type_id) => self.node(
2035                self.lookup_node(type_id)
2036                    .expect("BackRef target must exist in node_lookup"),
2037            ),
2038            _ => node,
2039        }
2040    }
2041
2042    /// Get the StructPlan if a node is a struct type.
2043    /// Follows BackRef nodes for recursive types.
2044    #[inline]
2045    pub fn as_struct_plan<'a>(&'a self, node: &'a TypePlanNode) -> Option<&'a StructPlan> {
2046        let resolved = self.resolve_backref(node);
2047        match &resolved.kind {
2048            TypePlanNodeKind::Struct(plan) => Some(plan),
2049            _ => None,
2050        }
2051    }
2052
2053    /// Get the EnumPlan if a node is an enum type.
2054    /// Follows BackRef nodes for recursive types.
2055    #[inline]
2056    pub fn as_enum_plan<'a>(&'a self, node: &'a TypePlanNode) -> Option<&'a EnumPlan> {
2057        let resolved = self.resolve_backref(node);
2058        match &resolved.kind {
2059            TypePlanNodeKind::Enum(plan) => Some(plan),
2060            _ => None,
2061        }
2062    }
2063
2064    /// Resolve a BackRef (by node ID) to get the actual node it points to.
2065    #[inline]
2066    pub fn resolve_backref_id(&self, node_id: NodeId) -> &TypePlanNode {
2067        let node = self.node(node_id);
2068        self.resolve_backref(node)
2069    }
2070
2071    /// Get the StructPlan for a node ID, if it's a struct type.
2072    /// Follows BackRef nodes for recursive types.
2073    #[inline]
2074    pub fn struct_plan_by_id(&self, node_id: NodeId) -> Option<&StructPlan> {
2075        self.as_struct_plan(self.node(node_id))
2076    }
2077
2078    /// Get the EnumPlan for a node ID, if it's an enum type.
2079    /// Follows BackRef nodes for recursive types.
2080    #[inline]
2081    pub fn enum_plan_by_id(&self, node_id: NodeId) -> Option<&EnumPlan> {
2082        self.as_enum_plan(self.node(node_id))
2083    }
2084
2085    // Navigation helpers that work with NodeId (returning NodeId for child nodes)
2086
2087    /// Get the child node ID for a struct field by index.
2088    /// Follows BackRef nodes for recursive types.
2089    #[inline]
2090    pub fn struct_field_node_id(&self, parent_id: NodeId, idx: usize) -> Option<NodeId> {
2091        let parent = self.node(parent_id);
2092        let resolved = self.resolve_backref(parent);
2093        let struct_plan = match &resolved.kind {
2094            TypePlanNodeKind::Struct(p) => p,
2095            _ => return None,
2096        };
2097        let fields = self.fields(struct_plan.fields);
2098        Some(fields.get(idx)?.type_node)
2099    }
2100
2101    /// Get the child node ID for an enum variant's field.
2102    /// Follows BackRef nodes for recursive types.
2103    #[inline]
2104    pub fn enum_variant_field_node_id(
2105        &self,
2106        parent_id: NodeId,
2107        variant_idx: usize,
2108        field_idx: usize,
2109    ) -> Option<NodeId> {
2110        let parent = self.node(parent_id);
2111        let resolved = self.resolve_backref(parent);
2112        let enum_plan = match &resolved.kind {
2113            TypePlanNodeKind::Enum(p) => p,
2114            _ => return None,
2115        };
2116        let variants = self.variants(enum_plan.variants);
2117        let variant = variants.get(variant_idx)?;
2118        let fields = self.fields(variant.fields);
2119        Some(fields.get(field_idx)?.type_node)
2120    }
2121
2122    /// Get the child node ID for list/array items.
2123    #[inline]
2124    pub fn list_item_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2125        let parent = self.node(parent_id);
2126        match &parent.strategy {
2127            DeserStrategy::List { item_node, .. } | DeserStrategy::Array { item_node, .. } => {
2128                Some(*item_node)
2129            }
2130            DeserStrategy::BackRef { target_type_id } => {
2131                let target = self.lookup_node(target_type_id)?;
2132                self.list_item_node_id(target)
2133            }
2134            _ => None,
2135        }
2136    }
2137
2138    /// Get the child node ID for set items.
2139    #[inline]
2140    pub fn set_item_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2141        let parent = self.node(parent_id);
2142        match &parent.strategy {
2143            DeserStrategy::Set { item_node } => Some(*item_node),
2144            DeserStrategy::BackRef { target_type_id } => {
2145                let target = self.lookup_node(target_type_id)?;
2146                self.set_item_node_id(target)
2147            }
2148            _ => None,
2149        }
2150    }
2151
2152    /// Get the child node ID for map keys.
2153    #[inline]
2154    pub fn map_key_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2155        let parent = self.node(parent_id);
2156        match &parent.strategy {
2157            DeserStrategy::Map { key_node, .. } => Some(*key_node),
2158            DeserStrategy::BackRef { target_type_id } => {
2159                let target = self.lookup_node(target_type_id)?;
2160                self.map_key_node_id(target)
2161            }
2162            _ => None,
2163        }
2164    }
2165
2166    /// Get the child node ID for map values.
2167    #[inline]
2168    pub fn map_value_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2169        let parent = self.node(parent_id);
2170        match &parent.strategy {
2171            DeserStrategy::Map { value_node, .. } => Some(*value_node),
2172            DeserStrategy::BackRef { target_type_id } => {
2173                let target = self.lookup_node(target_type_id)?;
2174                self.map_value_node_id(target)
2175            }
2176            _ => None,
2177        }
2178    }
2179
2180    /// Get the child node ID for Option's Some variant.
2181    #[inline]
2182    pub fn option_some_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2183        let parent = self.node(parent_id);
2184        match &parent.strategy {
2185            DeserStrategy::Option { some_node, .. } => Some(*some_node),
2186            DeserStrategy::BackRef { target_type_id } => {
2187                let target = self.lookup_node(target_type_id)?;
2188                self.option_some_node_id(target)
2189            }
2190            _ => None,
2191        }
2192    }
2193
2194    /// Get the child node IDs for Result's Ok and Err variants.
2195    #[inline]
2196    pub fn result_nodes_id(&self, parent_id: NodeId) -> Option<(NodeId, NodeId)> {
2197        let parent = self.node(parent_id);
2198        match &parent.strategy {
2199            DeserStrategy::Result {
2200                ok_node, err_node, ..
2201            } => Some((*ok_node, *err_node)),
2202            DeserStrategy::BackRef { target_type_id } => {
2203                let target = self.lookup_node(target_type_id)?;
2204                self.result_nodes_id(target)
2205            }
2206            _ => None,
2207        }
2208    }
2209
2210    /// Get the child node ID for smart pointer inner type.
2211    #[inline]
2212    pub fn pointer_inner_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2213        let parent = self.node(parent_id);
2214        match &parent.strategy {
2215            DeserStrategy::Pointer { pointee_node, .. } => Some(*pointee_node),
2216            DeserStrategy::BackRef { target_type_id } => {
2217                let target = self.lookup_node(target_type_id)?;
2218                self.pointer_inner_node_id(target)
2219            }
2220            _ => None,
2221        }
2222    }
2223
2224    /// Get the child node ID for transparent convert inner type.
2225    #[inline]
2226    pub fn inner_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2227        let parent = self.node(parent_id);
2228        if parent.shape.inner.is_some() {
2229            match &parent.strategy {
2230                DeserStrategy::TransparentConvert { inner_node } => Some(*inner_node),
2231                _ => None,
2232            }
2233        } else {
2234            None
2235        }
2236    }
2237
2238    pub(crate) fn empty() -> TypePlanCore {
2239        TypePlanCore {
2240            nodes: Arena::new(),
2241            fields: Arena::new(),
2242            variants: Arena::new(),
2243            validators: Arena::new(),
2244            field_entries: Arena::new(),
2245            buckets: Arena::new(),
2246            node_lookup: Vec::new(),
2247            root: NodeId::new(0),
2248        }
2249    }
2250}
2251
2252#[cfg(test)]
2253mod tests {
2254    use super::*;
2255    use facet::Facet;
2256
2257    #[derive(Facet)]
2258    struct TestStruct {
2259        name: String,
2260        age: u32,
2261        email: Option<String>,
2262    }
2263
2264    #[derive(Facet)]
2265    #[repr(u8)]
2266    #[allow(dead_code)] // Fields used for reflection testing
2267    enum TestEnum {
2268        Unit,
2269        Tuple(u32),
2270        Struct { value: String },
2271    }
2272
2273    #[derive(Facet)]
2274    struct RecursiveStruct {
2275        value: u32,
2276        // Recursive: contains Option<Box<Self>>
2277        next: Option<Box<RecursiveStruct>>,
2278    }
2279
2280    #[test]
2281    fn test_typeplan_build_reuses_cached_core() {
2282        #[derive(Facet)]
2283        struct CacheProbe {
2284            value: u32,
2285        }
2286
2287        let first = TypePlan::<CacheProbe>::build().unwrap().core();
2288        let second = TypePlan::<CacheProbe>::build().unwrap().core();
2289        assert!(Arc::ptr_eq(&first, &second));
2290
2291        // SAFETY: CacheProbe::SHAPE comes from Facet metadata for a real type.
2292        let third =
2293            unsafe { TypePlanCore::from_shape(<CacheProbe as facet_core::Facet<'static>>::SHAPE) }
2294                .unwrap();
2295        assert!(Arc::ptr_eq(&first, &third));
2296    }
2297
2298    #[test]
2299    fn test_typeplan_struct() {
2300        let plan = TypePlan::<TestStruct>::build().unwrap();
2301        let root = plan.root();
2302        let core = plan.core();
2303
2304        assert_eq!(root.shape, TestStruct::SHAPE);
2305        assert!(!root.has_default);
2306
2307        match &root.kind {
2308            TypePlanNodeKind::Struct(struct_plan) => {
2309                let fields = core.fields(struct_plan.fields);
2310                assert_eq!(fields.len(), 3);
2311                assert!(!struct_plan.has_flatten);
2312
2313                // Check field lookup
2314                assert_eq!(struct_plan.field_lookup.find("name", &core), Some(0));
2315                assert_eq!(struct_plan.field_lookup.find("age", &core), Some(1));
2316                assert_eq!(struct_plan.field_lookup.find("email", &core), Some(2));
2317                assert_eq!(struct_plan.field_lookup.find("unknown", &core), None);
2318
2319                // Check field metadata
2320                assert_eq!(fields[0].name, "name");
2321                assert!(fields[0].is_required());
2322
2323                assert_eq!(fields[1].name, "age");
2324                assert!(fields[1].is_required());
2325
2326                assert_eq!(fields[2].name, "email");
2327                assert!(!fields[2].is_required()); // Option has implicit default
2328
2329                // Check child plan for Option field (field index 2 = third child)
2330                let email_node = core.struct_field_node(plan.root(), 2).unwrap();
2331                match &email_node.kind {
2332                    TypePlanNodeKind::Option => {
2333                        // inner should be String (scalar)
2334                        let inner_node = core.option_inner_node(email_node).unwrap();
2335                        match &inner_node.kind {
2336                            TypePlanNodeKind::Scalar => {}
2337                            other => panic!("Expected Scalar for String, got {:?}", other),
2338                        }
2339                    }
2340                    other => panic!("Expected Option, got {:?}", other),
2341                }
2342            }
2343            other => panic!("Expected Struct, got {:?}", other),
2344        }
2345    }
2346
2347    #[test]
2348    fn test_typeplan_enum() {
2349        let plan = TypePlan::<TestEnum>::build().unwrap();
2350        let root = plan.root();
2351        let core = plan.core();
2352
2353        assert_eq!(root.shape, TestEnum::SHAPE);
2354
2355        match &root.kind {
2356            TypePlanNodeKind::Enum(enum_plan) => {
2357                let variants = core.variants(enum_plan.variants);
2358                assert_eq!(enum_plan.num_variants, 3);
2359
2360                // Check variant lookup
2361                assert_eq!(enum_plan.variant_lookup.find("Unit"), Some(0));
2362                assert_eq!(enum_plan.variant_lookup.find("Tuple"), Some(1));
2363                assert_eq!(enum_plan.variant_lookup.find("Struct"), Some(2));
2364                assert_eq!(enum_plan.variant_lookup.find("Unknown"), None);
2365
2366                // Unit variant has no fields
2367                assert!(core.fields(variants[0].fields).is_empty());
2368
2369                // Tuple variant has 1 field
2370                assert_eq!(core.fields(variants[1].fields).len(), 1);
2371
2372                // Struct variant has 1 field
2373                let struct_variant_fields = core.fields(variants[2].fields);
2374                assert_eq!(struct_variant_fields.len(), 1);
2375                assert_eq!(variants[2].field_lookup.find("value", &core), Some(0));
2376            }
2377            other => panic!("Expected Enum, got {:?}", other),
2378        }
2379    }
2380
2381    #[test]
2382    fn test_typeplan_list() {
2383        let plan = TypePlan::<Vec<u32>>::build().unwrap();
2384        let root = plan.root();
2385        let core = plan.core();
2386
2387        match &root.kind {
2388            TypePlanNodeKind::List => {
2389                let item_node = core.list_item_node(plan.root()).unwrap();
2390                match &item_node.kind {
2391                    TypePlanNodeKind::Scalar => {}
2392                    other => panic!("Expected Scalar for u32, got {:?}", other),
2393                }
2394            }
2395            other => panic!("Expected List, got {:?}", other),
2396        }
2397    }
2398
2399    #[test]
2400    fn test_typeplan_recursive() {
2401        // This should NOT stack overflow - arena handles the cycle
2402        let plan = TypePlan::<RecursiveStruct>::build().unwrap();
2403        let root = plan.root();
2404        let core = plan.core();
2405
2406        match &root.kind {
2407            TypePlanNodeKind::Struct(struct_plan) => {
2408                let fields = core.fields(struct_plan.fields);
2409                assert_eq!(fields.len(), 2);
2410                assert_eq!(fields[0].name, "value");
2411                assert_eq!(fields[1].name, "next");
2412
2413                // The 'next' field is Option<Box<RecursiveStruct>>
2414                // Its child plan should eventually contain a BackRef
2415                let next_node = core.struct_field_node(plan.root(), 1).unwrap();
2416
2417                // Should be Option
2418                assert!(matches!(next_node.kind, TypePlanNodeKind::Option));
2419
2420                // Inner should be Pointer (Box)
2421                let inner_node = core.option_inner_node(next_node).unwrap();
2422                assert!(matches!(inner_node.kind, TypePlanNodeKind::Pointer));
2423
2424                // Pointee should be BackRef to root (or a struct with BackRef)
2425                let pointee_node = core.pointer_pointee_node(inner_node).unwrap();
2426
2427                // This should be a BackRef pointing to the root
2428                match &pointee_node.kind {
2429                    TypePlanNodeKind::BackRef(type_id) => {
2430                        // type_id should match the root's type
2431                        assert_eq!(type_id, &plan.root().shape.id);
2432                    }
2433                    _ => panic!(
2434                        "Expected BackRef for recursive type, got {:?}",
2435                        pointee_node.kind
2436                    ),
2437                }
2438            }
2439            other => panic!("Expected Struct, got {:?}", other),
2440        }
2441    }
2442
2443    #[test]
2444    fn test_field_lookup_small() {
2445        let lookup = FieldLookup::Small(smallvec::smallvec![
2446            FieldLookupEntry {
2447                name: "foo",
2448                index: 0,
2449                is_alias: false,
2450            },
2451            FieldLookupEntry {
2452                name: "bar",
2453                index: 1,
2454                is_alias: false,
2455            },
2456            FieldLookupEntry {
2457                name: "baz",
2458                index: 2,
2459                is_alias: false,
2460            },
2461        ]);
2462
2463        assert_eq!(lookup.find_small("foo"), Some(0));
2464        assert_eq!(lookup.find_small("bar"), Some(1));
2465        assert_eq!(lookup.find_small("baz"), Some(2));
2466        assert_eq!(lookup.find_small("qux"), None);
2467    }
2468
2469    #[test]
2470    fn test_variant_lookup_small() {
2471        let lookup = VariantLookup::Small(smallvec::smallvec![("A", 0), ("B", 1), ("C", 2)]);
2472
2473        assert_eq!(lookup.find("A"), Some(0));
2474        assert_eq!(lookup.find("B"), Some(1));
2475        assert_eq!(lookup.find("C"), Some(2));
2476        assert_eq!(lookup.find("D"), None);
2477    }
2478}