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 with builder_shape + try_from (like Yoke):
1343                    // build the builder_shape as a child so TransparentConvert can
1344                    // deserialize the cart then try_from it into the opaque type
1345                    Type::User(UserType::Opaque) | Type::Undefined
1346                        if shape.builder_shape.is_some() && shape.vtable.has_try_from() =>
1347                    {
1348                        children.push(self.build_node(shape.builder_shape.unwrap())?);
1349                        TypePlanNodeKind::Transparent
1350                    }
1351                    // Truly opaque types - no deserialization possible
1352                    Type::User(UserType::Opaque) | Type::Undefined => TypePlanNodeKind::Opaque,
1353                    _ => {
1354                        // Check for transparent wrappers (newtypes) as fallback
1355                        if let Some(inner) = shape.inner {
1356                            children.push(self.build_node(inner)?);
1357                            TypePlanNodeKind::Transparent
1358                        } else {
1359                            return Err(AllocError {
1360                                shape,
1361                                operation: "unsupported type for deserialization",
1362                            });
1363                        }
1364                    }
1365                }
1366            }
1367        };
1368        Ok((kind, children))
1369    }
1370
1371    /// Build a StructPlan with all field plans.
1372    fn build_struct_plan(
1373        &mut self,
1374        shape: &'static Shape,
1375        struct_def: &'static StructType,
1376    ) -> Result<StructPlan, AllocError> {
1377        let mut field_plans = Vec::with_capacity(struct_def.fields.len());
1378
1379        // Check if the container struct has #[facet(default)]
1380        let container_has_default = shape.is(Characteristic::Default);
1381
1382        for (index, field) in struct_def.fields.iter().enumerate() {
1383            // Build the type plan node for this field first
1384            let field_proxies = FieldProxies::from_field(field);
1385            let child_node = self.build_node_with_proxy(field.shape(), field_proxies)?;
1386
1387            // Build validators and fill rule
1388            let validators = self.extract_validators(field);
1389            let fill_rule = Self::determine_fill_rule(field, container_has_default);
1390
1391            // Create unified field plan
1392            field_plans
1393                .push(self.create_field_plan(index, field, child_node, fill_rule, validators));
1394        }
1395
1396        // Allocate fields into arena
1397        let has_flatten = field_plans.iter().any(|f| f.is_flattened);
1398        let fields = self.fields.alloc_extend(field_plans.iter().cloned());
1399
1400        // Build field lookup
1401        let field_lookup = self.build_field_lookup(&field_plans);
1402
1403        // Precompute deny_unknown_fields from shape attributes (avoids runtime attribute scanning)
1404        let deny_unknown_fields = shape.has_deny_unknown_fields_attr();
1405
1406        Ok(StructPlan {
1407            struct_def,
1408            fields,
1409            field_lookup,
1410            has_flatten,
1411            deny_unknown_fields,
1412        })
1413    }
1414
1415    /// Create a FieldPlan from its components.
1416    fn create_field_plan(
1417        &mut self,
1418        index: usize,
1419        field: &'static Field,
1420        type_node: NodeId,
1421        fill_rule: FillRule,
1422        validators: ValidatorRange,
1423    ) -> FieldPlan {
1424        let name = field.name;
1425        let effective_name = field.effective_name();
1426        let alias = field.alias;
1427        let is_flattened = field.is_flattened();
1428
1429        FieldPlan {
1430            // Metadata for matching/lookup
1431            field,
1432            name,
1433            effective_name,
1434            alias,
1435            is_flattened,
1436            type_node,
1437            // Initialization/validation
1438            index,
1439            offset: field.offset,
1440            field_shape: field.shape(),
1441            fill_rule,
1442            validators,
1443        }
1444    }
1445
1446    /// Build a field lookup from field plans.
1447    fn build_field_lookup(&mut self, field_plans: &[FieldPlan]) -> FieldLookup {
1448        let mut entries: Vec<FieldLookupEntry> = Vec::with_capacity(field_plans.len() * 2);
1449
1450        for (index, field_plan) in field_plans.iter().enumerate() {
1451            // Add primary name
1452            entries.push(FieldLookupEntry {
1453                name: field_plan.effective_name,
1454                index,
1455                is_alias: false,
1456            });
1457
1458            // Add alias if present
1459            if let Some(alias) = field_plan.alias {
1460                entries.push(FieldLookupEntry {
1461                    name: alias,
1462                    index,
1463                    is_alias: true,
1464                });
1465            }
1466        }
1467
1468        self.build_field_lookup_from_entries(entries)
1469    }
1470
1471    /// Build lookup structure from entries.
1472    fn build_field_lookup_from_entries(&mut self, entries: Vec<FieldLookupEntry>) -> FieldLookup {
1473        let total_entries = entries.len();
1474        if total_entries <= LOOKUP_THRESHOLD {
1475            return FieldLookup::Small(entries.into_iter().collect());
1476        }
1477
1478        // Choose prefix length: 8 bytes if most keys are long, otherwise 4
1479        let long_key_count = entries.iter().filter(|e| e.name.len() >= 8).count();
1480        let prefix_len = if long_key_count > total_entries / 2 {
1481            8
1482        } else {
1483            4
1484        };
1485
1486        // Group entries by prefix
1487        let mut prefix_map: hashbrown::HashMap<u64, Vec<FieldLookupEntry>> =
1488            hashbrown::HashMap::new();
1489        for entry in entries {
1490            let prefix = compute_prefix(entry.name, prefix_len);
1491            prefix_map.entry(prefix).or_default().push(entry);
1492        }
1493
1494        // Build sorted bucket list and flattened entries
1495        let mut bucket_list: Vec<_> = prefix_map.into_iter().collect();
1496        bucket_list.sort_by_key(|(prefix, _)| *prefix);
1497
1498        let mut all_entries = Vec::with_capacity(total_entries);
1499        let mut bucket_data = Vec::with_capacity(bucket_list.len());
1500
1501        for (prefix, bucket_entries) in bucket_list {
1502            let start = all_entries.len() as u32;
1503            let count = bucket_entries.len() as u32;
1504            bucket_data.push((prefix, start, count));
1505            all_entries.extend(bucket_entries);
1506        }
1507
1508        // Allocate into arenas
1509        let entries_range = self.field_entries.alloc_extend(all_entries);
1510        let buckets_range = self.buckets.alloc_extend(bucket_data);
1511
1512        FieldLookup::PrefixBuckets {
1513            prefix_len,
1514            entries: entries_range,
1515            buckets: buckets_range,
1516        }
1517    }
1518
1519    /// Determine how to fill a field that wasn't set.
1520    fn determine_fill_rule(field: &'static Field, container_has_default: bool) -> FillRule {
1521        let field_shape = field.shape();
1522
1523        // Check for explicit default on the field (#[facet(default)] or #[facet(default = expr)])
1524        if let Some(default_source) = field.default_source() {
1525            let field_default = match default_source {
1526                DefaultSource::Custom(f) => FieldDefault::Custom(*f),
1527                DefaultSource::FromTrait => FieldDefault::FromTrait(field_shape),
1528            };
1529            return FillRule::Defaultable(field_default);
1530        }
1531
1532        // Option<T> without explicit default implicitly defaults to None
1533        let is_option = matches!(field_shape.def, Def::Option(_));
1534        if is_option && field_shape.is(Characteristic::Default) {
1535            return FillRule::Defaultable(FieldDefault::FromTrait(field_shape));
1536        }
1537
1538        // Skipped fields MUST have a default (they're never deserialized)
1539        if field.should_skip_deserializing() && field_shape.is(Characteristic::Default) {
1540            return FillRule::Defaultable(FieldDefault::FromTrait(field_shape));
1541        }
1542
1543        // Empty structs/tuples (like `()`) are trivially defaultable
1544        if let Type::User(UserType::Struct(struct_type)) = field_shape.ty
1545            && struct_type.fields.is_empty()
1546            && field_shape.is(Characteristic::Default)
1547        {
1548            return FillRule::Defaultable(FieldDefault::FromTrait(field_shape));
1549        }
1550
1551        // If container has #[facet(default)] and the field's type implements Default,
1552        // use the type's Default impl
1553        if container_has_default && field_shape.is(Characteristic::Default) {
1554            return FillRule::Defaultable(FieldDefault::FromTrait(field_shape));
1555        }
1556
1557        // Field is required - must be set during deserialization
1558        FillRule::Required
1559    }
1560
1561    /// Extract validators from field attributes.
1562    fn extract_validators(&mut self, field: &'static Field) -> ValidatorRange {
1563        let mut validators = Vec::new();
1564        let field_shape = field.shape();
1565        // Precompute scalar type once - used by validators that need it
1566        let scalar_type = field_shape.scalar_type();
1567
1568        for attr in field.attributes.iter() {
1569            if attr.ns != Some("validate") {
1570                continue;
1571            }
1572
1573            let kind = match attr.key {
1574                "custom" => {
1575                    // SAFETY: validate::custom attribute stores a ValidatorFn
1576                    let validator_fn = unsafe { *attr.data.ptr().get::<ValidatorFn>() };
1577                    ValidatorKind::Custom(validator_fn)
1578                }
1579                "min" => {
1580                    let limit = *attr
1581                        .get_as::<i64>()
1582                        .expect("validate::min attribute must contain i64");
1583                    let scalar_type =
1584                        scalar_type.expect("validate::min requires numeric field type");
1585                    ValidatorKind::Min { limit, scalar_type }
1586                }
1587                "max" => {
1588                    let limit = *attr
1589                        .get_as::<i64>()
1590                        .expect("validate::max attribute must contain i64");
1591                    let scalar_type =
1592                        scalar_type.expect("validate::max requires numeric field type");
1593                    ValidatorKind::Max { limit, scalar_type }
1594                }
1595                "min_length" => {
1596                    let limit = *attr
1597                        .get_as::<usize>()
1598                        .expect("validate::min_length attribute must contain usize");
1599                    let scalar_type =
1600                        scalar_type.expect("validate::min_length requires string field type");
1601                    ValidatorKind::MinLength { limit, scalar_type }
1602                }
1603                "max_length" => {
1604                    let limit = *attr
1605                        .get_as::<usize>()
1606                        .expect("validate::max_length attribute must contain usize");
1607                    let scalar_type =
1608                        scalar_type.expect("validate::max_length requires string field type");
1609                    ValidatorKind::MaxLength { limit, scalar_type }
1610                }
1611                "email" => {
1612                    let scalar_type =
1613                        scalar_type.expect("validate::email requires string field type");
1614                    ValidatorKind::Email { scalar_type }
1615                }
1616                "url" => {
1617                    let scalar_type =
1618                        scalar_type.expect("validate::url requires string field type");
1619                    ValidatorKind::Url { scalar_type }
1620                }
1621                "regex" => {
1622                    let pattern = *attr
1623                        .get_as::<&'static str>()
1624                        .expect("validate::regex attribute must contain &'static str");
1625                    let scalar_type =
1626                        scalar_type.expect("validate::regex requires string field type");
1627                    ValidatorKind::Regex {
1628                        pattern,
1629                        scalar_type,
1630                    }
1631                }
1632                "contains" => {
1633                    let needle = *attr
1634                        .get_as::<&'static str>()
1635                        .expect("validate::contains attribute must contain &'static str");
1636                    let scalar_type =
1637                        scalar_type.expect("validate::contains requires string field type");
1638                    ValidatorKind::Contains {
1639                        needle,
1640                        scalar_type,
1641                    }
1642                }
1643                _ => continue, // Unknown validator, skip
1644            };
1645
1646            validators.push(PrecomputedValidator { kind });
1647        }
1648
1649        self.validators.alloc_extend(validators)
1650    }
1651
1652    /// Build an EnumPlan with all field plans for each variant.
1653    fn build_enum_plan(&mut self, enum_def: &'static EnumType) -> Result<EnumPlan, AllocError> {
1654        let mut variant_metas = Vec::with_capacity(enum_def.variants.len());
1655
1656        for variant in enum_def.variants.iter() {
1657            let mut field_plans = Vec::with_capacity(variant.data.fields.len());
1658
1659            for (index, field) in variant.data.fields.iter().enumerate() {
1660                // Build the type plan node for this field
1661                let field_proxies = FieldProxies::from_field(field);
1662                let child_node = self.build_node_with_proxy(field.shape(), field_proxies)?;
1663
1664                // Build validators and fill rule (enums don't have container-level default)
1665                let validators = self.extract_validators(field);
1666                let fill_rule = Self::determine_fill_rule(field, false);
1667
1668                // Create unified field plan
1669                field_plans
1670                    .push(self.create_field_plan(index, field, child_node, fill_rule, validators));
1671            }
1672
1673            let has_flatten = field_plans.iter().any(|f| f.is_flattened);
1674            let fields = self.fields.alloc_extend(field_plans.iter().cloned());
1675            let field_lookup = self.build_field_lookup(&field_plans);
1676
1677            variant_metas.push(VariantPlanMeta {
1678                variant,
1679                name: variant.effective_name(),
1680                fields,
1681                field_lookup,
1682                has_flatten,
1683            });
1684        }
1685
1686        let variants = self.variants.alloc_extend(variant_metas.iter().cloned());
1687        let variant_lookup = self.build_variant_lookup(&variant_metas);
1688        let num_variants = variant_metas.len();
1689
1690        // Find the index of the #[facet(other)] variant, if any
1691        let other_variant_idx = variant_metas.iter().position(|v| v.variant.is_other());
1692
1693        Ok(EnumPlan {
1694            enum_def,
1695            variants,
1696            variant_lookup,
1697            num_variants,
1698            other_variant_idx,
1699        })
1700    }
1701
1702    /// Build a variant lookup from variant metadata.
1703    ///
1704    /// Note: `#[facet(other)]` variants are excluded from the lookup because they
1705    /// should only be used as a fallback when no other variant matches. Including
1706    /// them would cause serialized `#[facet(other)]` values to deserialize via
1707    /// the normal path instead of the fallback path.
1708    fn build_variant_lookup(&self, variants: &[VariantPlanMeta]) -> VariantLookup {
1709        let entries: Vec<_> = variants
1710            .iter()
1711            .enumerate()
1712            .filter(|(_, v)| !v.variant.is_other())
1713            .map(|(i, v)| (v.name, i))
1714            .collect();
1715
1716        if entries.len() <= LOOKUP_THRESHOLD {
1717            VariantLookup::Small(entries.into_iter().collect())
1718        } else {
1719            let mut sorted = entries;
1720            sorted.sort_by_key(|(name, _)| *name);
1721            VariantLookup::Sorted(sorted)
1722        }
1723    }
1724}
1725
1726impl<'facet, T: facet_core::Facet<'facet> + ?Sized> TypePlan<T> {
1727    /// Build a TypePlan for type `T`.
1728    ///
1729    /// The type parameter provides compile-time safety: you cannot accidentally
1730    /// pass a `TypePlan<Foo>` where `TypePlan<Bar>` is expected.
1731    ///
1732    /// Note: TypePlan can be built for any `Facet<'_>` type because the `SHAPE`
1733    /// is always `'static`. The lifetime parameter on `Facet` only affects the
1734    /// runtime deserialized values, not the type metadata.
1735    ///
1736    /// # Example
1737    ///
1738    /// ```ignore
1739    /// use facet_reflect::TypePlan;
1740    ///
1741    /// let plan = TypePlan::<MyStruct>::build()?;
1742    /// ```
1743    pub fn build() -> Result<Self, AllocError> {
1744        // SAFETY: T::SHAPE comes from Facet metadata for a real type T.
1745        let core = unsafe { TypePlanCore::from_shape(T::SHAPE)? };
1746
1747        Ok(TypePlan {
1748            core,
1749            _marker: core::marker::PhantomData,
1750        })
1751    }
1752
1753    /// Build a TypePlan with format-specific proxy resolution.
1754    ///
1755    /// **Deprecated**: Format namespace is no longer needed at build time.
1756    /// TypePlan now stores proxy nodes for all formats, and the format-specific
1757    /// proxy is selected at runtime during deserialization.
1758    ///
1759    /// This method is kept for API compatibility but is equivalent to `build()`.
1760    #[deprecated(
1761        since = "0.44.0",
1762        note = "format namespace no longer needed at build time; use build() instead"
1763    )]
1764    pub fn build_for_format(_format_namespace: Option<&'static str>) -> Result<Self, AllocError> {
1765        Self::build()
1766    }
1767
1768    /// Get a reference to the internal core.
1769    #[inline]
1770    pub fn core(&self) -> Arc<TypePlanCore> {
1771        self.core.clone()
1772    }
1773
1774    /// Get the root node.
1775    #[inline]
1776    pub fn root(&self) -> &TypePlanNode {
1777        self.core.root()
1778    }
1779}
1780
1781impl TypePlanCore {
1782    /// Build a TypePlanCore directly from a shape, with process-global caching.
1783    ///
1784    /// Under `std`, one plan is cached per unique shape (`&'static Shape`) for
1785    /// the lifetime of the process. In `no_std`, this builds a fresh plan each call.
1786    ///
1787    /// # Safety
1788    ///
1789    /// The caller must ensure that the shape is valid and corresponds to a real type.
1790    /// Using an incorrect or maliciously crafted shape can lead to undefined behavior
1791    /// when materializing values.
1792    pub unsafe fn from_shape(shape: &'static Shape) -> Result<Arc<Self>, AllocError> {
1793        #[cfg(feature = "std")]
1794        {
1795            let mut guard = type_plan_cache()
1796                .lock()
1797                .unwrap_or_else(|poison| poison.into_inner());
1798
1799            if let Some(plan) = guard.get(&shape) {
1800                return Ok(Arc::clone(plan));
1801            }
1802
1803            // SAFETY: caller guarantees the shape is valid.
1804            let plan = unsafe { Self::build_uncached(shape)? };
1805            guard.insert(shape, Arc::clone(&plan));
1806            Ok(plan)
1807        }
1808
1809        #[cfg(not(feature = "std"))]
1810        {
1811            // SAFETY: caller guarantees the shape is valid.
1812            unsafe { Self::build_uncached(shape) }
1813        }
1814    }
1815
1816    /// Build a TypePlanCore from a shape without touching the global cache.
1817    ///
1818    /// # Safety
1819    ///
1820    /// Same safety contract as [`Self::from_shape`].
1821    unsafe fn build_uncached(shape: &'static Shape) -> Result<Arc<Self>, AllocError> {
1822        let mut builder = TypePlanBuilder::new();
1823        let root = builder.build_node(shape)?;
1824        Ok(Arc::new(builder.finish(root)))
1825    }
1826
1827    /// Get the root node.
1828    #[inline]
1829    pub fn root(&self) -> &TypePlanNode {
1830        self.node(self.root)
1831    }
1832
1833    /// Get the root node index.
1834    #[inline]
1835    pub fn root_id(&self) -> NodeId {
1836        self.root
1837    }
1838
1839    /// Get a node by its index.
1840    #[inline]
1841    pub fn node(&self, idx: NodeId) -> &TypePlanNode {
1842        self.nodes.get(idx)
1843    }
1844
1845    /// Get a field by its index.
1846    #[inline]
1847    pub fn field(&self, idx: Idx<FieldPlan>) -> &FieldPlan {
1848        self.fields.get(idx)
1849    }
1850
1851    /// Get a slice of fields from a range.
1852    #[inline]
1853    pub fn fields(&self, range: FieldRange) -> &[FieldPlan] {
1854        self.fields.get_slice(range)
1855    }
1856
1857    /// Get a variant by its index.
1858    #[inline]
1859    pub fn variant(&self, idx: Idx<VariantPlanMeta>) -> &VariantPlanMeta {
1860        self.variants.get(idx)
1861    }
1862
1863    /// Get a slice of variants from a range.
1864    #[inline]
1865    pub fn variants(&self, range: VariantRange) -> &[VariantPlanMeta] {
1866        self.variants.get_slice(range)
1867    }
1868
1869    /// Get a slice of validators from a range.
1870    #[inline]
1871    pub fn validators(&self, range: ValidatorRange) -> &[PrecomputedValidator] {
1872        self.validators.get_slice(range)
1873    }
1874
1875    /// Look up a node by TypeId using binary search on the sorted lookup table.
1876    #[inline]
1877    fn lookup_node(&self, type_id: &ConstTypeId) -> Option<NodeId> {
1878        let idx = self
1879            .node_lookup
1880            .binary_search_by_key(type_id, |(id, _)| *id)
1881            .ok()?;
1882        Some(self.node_lookup[idx].1)
1883    }
1884
1885    // Navigation helpers
1886
1887    /// Get the child node for a struct field by index.
1888    /// Follows BackRef nodes for recursive types.
1889    #[inline]
1890    pub fn struct_field_node(&self, parent: &TypePlanNode, idx: usize) -> Option<&TypePlanNode> {
1891        let resolved = self.resolve_backref(parent);
1892        let struct_plan = match &resolved.kind {
1893            TypePlanNodeKind::Struct(p) => p,
1894            _ => return None,
1895        };
1896        let fields = self.fields(struct_plan.fields);
1897        Some(self.node(fields.get(idx)?.type_node))
1898    }
1899
1900    /// Get the child node for an enum variant's field.
1901    /// Follows BackRef nodes for recursive types.
1902    #[inline]
1903    pub fn enum_variant_field_node(
1904        &self,
1905        parent: &TypePlanNode,
1906        variant_idx: usize,
1907        field_idx: usize,
1908    ) -> Option<&TypePlanNode> {
1909        let resolved = self.resolve_backref(parent);
1910        let enum_plan = match &resolved.kind {
1911            TypePlanNodeKind::Enum(p) => p,
1912            _ => return None,
1913        };
1914        let variants = self.variants(enum_plan.variants);
1915        let variant = variants.get(variant_idx)?;
1916        let fields = self.fields(variant.fields);
1917        Some(self.node(fields.get(field_idx)?.type_node))
1918    }
1919
1920    /// Get the child node for list/array items.
1921    #[inline]
1922    pub fn list_item_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1923        match &parent.strategy {
1924            DeserStrategy::List { item_node, .. } | DeserStrategy::Array { item_node, .. } => {
1925                Some(self.node(*item_node))
1926            }
1927            DeserStrategy::BackRef { target_type_id } => {
1928                let target = self.lookup_node(target_type_id)?;
1929                self.list_item_node(self.node(target))
1930            }
1931            _ => None,
1932        }
1933    }
1934
1935    /// Get the child node for set items.
1936    #[inline]
1937    pub fn set_item_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1938        match &parent.strategy {
1939            DeserStrategy::Set { item_node } => Some(self.node(*item_node)),
1940            DeserStrategy::BackRef { target_type_id } => {
1941                let target = self.lookup_node(target_type_id)?;
1942                self.set_item_node(self.node(target))
1943            }
1944            _ => None,
1945        }
1946    }
1947
1948    /// Get the child node for map keys.
1949    #[inline]
1950    pub fn map_key_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1951        match &parent.strategy {
1952            DeserStrategy::Map { key_node, .. } => Some(self.node(*key_node)),
1953            DeserStrategy::BackRef { target_type_id } => {
1954                let target = self.lookup_node(target_type_id)?;
1955                self.map_key_node(self.node(target))
1956            }
1957            _ => None,
1958        }
1959    }
1960
1961    /// Get the child node for map values.
1962    #[inline]
1963    pub fn map_value_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1964        match &parent.strategy {
1965            DeserStrategy::Map { value_node, .. } => Some(self.node(*value_node)),
1966            DeserStrategy::BackRef { target_type_id } => {
1967                let target = self.lookup_node(target_type_id)?;
1968                self.map_value_node(self.node(target))
1969            }
1970            _ => None,
1971        }
1972    }
1973
1974    /// Get the child node for Option inner type.
1975    #[inline]
1976    pub fn option_inner_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1977        match &parent.strategy {
1978            DeserStrategy::Option { some_node } => Some(self.node(*some_node)),
1979            DeserStrategy::BackRef { target_type_id } => {
1980                let target = self.lookup_node(target_type_id)?;
1981                self.option_inner_node(self.node(target))
1982            }
1983            _ => None,
1984        }
1985    }
1986
1987    /// Get the child node for Result Ok type.
1988    #[inline]
1989    pub fn result_ok_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1990        match &parent.strategy {
1991            DeserStrategy::Result { ok_node, .. } => Some(self.node(*ok_node)),
1992            DeserStrategy::BackRef { target_type_id } => {
1993                let target = self.lookup_node(target_type_id)?;
1994                self.result_ok_node(self.node(target))
1995            }
1996            _ => None,
1997        }
1998    }
1999
2000    /// Get the child node for Result Err type.
2001    #[inline]
2002    pub fn result_err_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
2003        match &parent.strategy {
2004            DeserStrategy::Result { err_node, .. } => Some(self.node(*err_node)),
2005            DeserStrategy::BackRef { target_type_id } => {
2006                let target = self.lookup_node(target_type_id)?;
2007                self.result_err_node(self.node(target))
2008            }
2009            _ => None,
2010        }
2011    }
2012
2013    /// Get the child node for pointer pointee.
2014    #[inline]
2015    pub fn pointer_pointee_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
2016        match &parent.strategy {
2017            DeserStrategy::Pointer { pointee_node } => Some(self.node(*pointee_node)),
2018            DeserStrategy::BackRef { target_type_id } => {
2019                let target = self.lookup_node(target_type_id)?;
2020                self.pointer_pointee_node(self.node(target))
2021            }
2022            _ => None,
2023        }
2024    }
2025
2026    /// Get the child node for shape.inner navigation (used by begin_inner).
2027    #[inline]
2028    pub fn inner_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
2029        if parent.shape.inner.is_some() {
2030            match &parent.strategy {
2031                DeserStrategy::TransparentConvert { inner_node } => Some(self.node(*inner_node)),
2032                _ => None,
2033            }
2034        } else {
2035            None
2036        }
2037    }
2038
2039    /// Resolve a BackRef to get the actual node it points to.
2040    #[inline]
2041    pub fn resolve_backref<'a>(&'a self, node: &'a TypePlanNode) -> &'a TypePlanNode {
2042        match &node.kind {
2043            TypePlanNodeKind::BackRef(type_id) => self.node(
2044                self.lookup_node(type_id)
2045                    .expect("BackRef target must exist in node_lookup"),
2046            ),
2047            _ => node,
2048        }
2049    }
2050
2051    /// Get the StructPlan if a node is a struct type.
2052    /// Follows BackRef nodes for recursive types.
2053    #[inline]
2054    pub fn as_struct_plan<'a>(&'a self, node: &'a TypePlanNode) -> Option<&'a StructPlan> {
2055        let resolved = self.resolve_backref(node);
2056        match &resolved.kind {
2057            TypePlanNodeKind::Struct(plan) => Some(plan),
2058            _ => None,
2059        }
2060    }
2061
2062    /// Get the EnumPlan if a node is an enum type.
2063    /// Follows BackRef nodes for recursive types.
2064    #[inline]
2065    pub fn as_enum_plan<'a>(&'a self, node: &'a TypePlanNode) -> Option<&'a EnumPlan> {
2066        let resolved = self.resolve_backref(node);
2067        match &resolved.kind {
2068            TypePlanNodeKind::Enum(plan) => Some(plan),
2069            _ => None,
2070        }
2071    }
2072
2073    /// Resolve a BackRef (by node ID) to get the actual node it points to.
2074    #[inline]
2075    pub fn resolve_backref_id(&self, node_id: NodeId) -> &TypePlanNode {
2076        let node = self.node(node_id);
2077        self.resolve_backref(node)
2078    }
2079
2080    /// Get the StructPlan for a node ID, if it's a struct type.
2081    /// Follows BackRef nodes for recursive types.
2082    #[inline]
2083    pub fn struct_plan_by_id(&self, node_id: NodeId) -> Option<&StructPlan> {
2084        self.as_struct_plan(self.node(node_id))
2085    }
2086
2087    /// Get the EnumPlan for a node ID, if it's an enum type.
2088    /// Follows BackRef nodes for recursive types.
2089    #[inline]
2090    pub fn enum_plan_by_id(&self, node_id: NodeId) -> Option<&EnumPlan> {
2091        self.as_enum_plan(self.node(node_id))
2092    }
2093
2094    // Navigation helpers that work with NodeId (returning NodeId for child nodes)
2095
2096    /// Get the child node ID for a struct field by index.
2097    /// Follows BackRef nodes for recursive types.
2098    #[inline]
2099    pub fn struct_field_node_id(&self, parent_id: NodeId, idx: usize) -> Option<NodeId> {
2100        let parent = self.node(parent_id);
2101        let resolved = self.resolve_backref(parent);
2102        let struct_plan = match &resolved.kind {
2103            TypePlanNodeKind::Struct(p) => p,
2104            _ => return None,
2105        };
2106        let fields = self.fields(struct_plan.fields);
2107        Some(fields.get(idx)?.type_node)
2108    }
2109
2110    /// Get the child node ID for an enum variant's field.
2111    /// Follows BackRef nodes for recursive types.
2112    #[inline]
2113    pub fn enum_variant_field_node_id(
2114        &self,
2115        parent_id: NodeId,
2116        variant_idx: usize,
2117        field_idx: usize,
2118    ) -> Option<NodeId> {
2119        let parent = self.node(parent_id);
2120        let resolved = self.resolve_backref(parent);
2121        let enum_plan = match &resolved.kind {
2122            TypePlanNodeKind::Enum(p) => p,
2123            _ => return None,
2124        };
2125        let variants = self.variants(enum_plan.variants);
2126        let variant = variants.get(variant_idx)?;
2127        let fields = self.fields(variant.fields);
2128        Some(fields.get(field_idx)?.type_node)
2129    }
2130
2131    /// Get the child node ID for list/array items.
2132    #[inline]
2133    pub fn list_item_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2134        let parent = self.node(parent_id);
2135        match &parent.strategy {
2136            DeserStrategy::List { item_node, .. } | DeserStrategy::Array { item_node, .. } => {
2137                Some(*item_node)
2138            }
2139            DeserStrategy::BackRef { target_type_id } => {
2140                let target = self.lookup_node(target_type_id)?;
2141                self.list_item_node_id(target)
2142            }
2143            _ => None,
2144        }
2145    }
2146
2147    /// Get the child node ID for set items.
2148    #[inline]
2149    pub fn set_item_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2150        let parent = self.node(parent_id);
2151        match &parent.strategy {
2152            DeserStrategy::Set { item_node } => Some(*item_node),
2153            DeserStrategy::BackRef { target_type_id } => {
2154                let target = self.lookup_node(target_type_id)?;
2155                self.set_item_node_id(target)
2156            }
2157            _ => None,
2158        }
2159    }
2160
2161    /// Get the child node ID for map keys.
2162    #[inline]
2163    pub fn map_key_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2164        let parent = self.node(parent_id);
2165        match &parent.strategy {
2166            DeserStrategy::Map { key_node, .. } => Some(*key_node),
2167            DeserStrategy::BackRef { target_type_id } => {
2168                let target = self.lookup_node(target_type_id)?;
2169                self.map_key_node_id(target)
2170            }
2171            _ => None,
2172        }
2173    }
2174
2175    /// Get the child node ID for map values.
2176    #[inline]
2177    pub fn map_value_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2178        let parent = self.node(parent_id);
2179        match &parent.strategy {
2180            DeserStrategy::Map { value_node, .. } => Some(*value_node),
2181            DeserStrategy::BackRef { target_type_id } => {
2182                let target = self.lookup_node(target_type_id)?;
2183                self.map_value_node_id(target)
2184            }
2185            _ => None,
2186        }
2187    }
2188
2189    /// Get the child node ID for Option's Some variant.
2190    #[inline]
2191    pub fn option_some_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2192        let parent = self.node(parent_id);
2193        match &parent.strategy {
2194            DeserStrategy::Option { some_node, .. } => Some(*some_node),
2195            DeserStrategy::BackRef { target_type_id } => {
2196                let target = self.lookup_node(target_type_id)?;
2197                self.option_some_node_id(target)
2198            }
2199            _ => None,
2200        }
2201    }
2202
2203    /// Get the child node IDs for Result's Ok and Err variants.
2204    #[inline]
2205    pub fn result_nodes_id(&self, parent_id: NodeId) -> Option<(NodeId, NodeId)> {
2206        let parent = self.node(parent_id);
2207        match &parent.strategy {
2208            DeserStrategy::Result {
2209                ok_node, err_node, ..
2210            } => Some((*ok_node, *err_node)),
2211            DeserStrategy::BackRef { target_type_id } => {
2212                let target = self.lookup_node(target_type_id)?;
2213                self.result_nodes_id(target)
2214            }
2215            _ => None,
2216        }
2217    }
2218
2219    /// Get the child node ID for smart pointer inner type.
2220    #[inline]
2221    pub fn pointer_inner_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2222        let parent = self.node(parent_id);
2223        match &parent.strategy {
2224            DeserStrategy::Pointer { pointee_node, .. } => Some(*pointee_node),
2225            DeserStrategy::BackRef { target_type_id } => {
2226                let target = self.lookup_node(target_type_id)?;
2227                self.pointer_inner_node_id(target)
2228            }
2229            _ => None,
2230        }
2231    }
2232
2233    /// Get the child node ID for transparent convert inner type.
2234    #[inline]
2235    pub fn inner_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2236        let parent = self.node(parent_id);
2237        if parent.shape.inner.is_some() {
2238            match &parent.strategy {
2239                DeserStrategy::TransparentConvert { inner_node } => Some(*inner_node),
2240                _ => None,
2241            }
2242        } else {
2243            None
2244        }
2245    }
2246
2247    pub(crate) fn empty() -> TypePlanCore {
2248        TypePlanCore {
2249            nodes: Arena::new(),
2250            fields: Arena::new(),
2251            variants: Arena::new(),
2252            validators: Arena::new(),
2253            field_entries: Arena::new(),
2254            buckets: Arena::new(),
2255            node_lookup: Vec::new(),
2256            root: NodeId::new(0),
2257        }
2258    }
2259}
2260
2261#[cfg(test)]
2262mod tests {
2263    use super::*;
2264    use facet::Facet;
2265
2266    #[derive(Facet)]
2267    struct TestStruct {
2268        name: String,
2269        age: u32,
2270        email: Option<String>,
2271    }
2272
2273    #[derive(Facet)]
2274    #[repr(u8)]
2275    #[allow(dead_code)] // Fields used for reflection testing
2276    enum TestEnum {
2277        Unit,
2278        Tuple(u32),
2279        Struct { value: String },
2280    }
2281
2282    #[derive(Facet)]
2283    struct RecursiveStruct {
2284        value: u32,
2285        // Recursive: contains Option<Box<Self>>
2286        next: Option<Box<RecursiveStruct>>,
2287    }
2288
2289    #[test]
2290    fn test_typeplan_build_reuses_cached_core() {
2291        #[derive(Facet)]
2292        struct CacheProbe {
2293            value: u32,
2294        }
2295
2296        let first = TypePlan::<CacheProbe>::build().unwrap().core();
2297        let second = TypePlan::<CacheProbe>::build().unwrap().core();
2298        assert!(Arc::ptr_eq(&first, &second));
2299
2300        // SAFETY: CacheProbe::SHAPE comes from Facet metadata for a real type.
2301        let third =
2302            unsafe { TypePlanCore::from_shape(<CacheProbe as facet_core::Facet<'static>>::SHAPE) }
2303                .unwrap();
2304        assert!(Arc::ptr_eq(&first, &third));
2305    }
2306
2307    #[test]
2308    fn test_typeplan_struct() {
2309        let plan = TypePlan::<TestStruct>::build().unwrap();
2310        let root = plan.root();
2311        let core = plan.core();
2312
2313        assert_eq!(root.shape, TestStruct::SHAPE);
2314        assert!(!root.has_default);
2315
2316        match &root.kind {
2317            TypePlanNodeKind::Struct(struct_plan) => {
2318                let fields = core.fields(struct_plan.fields);
2319                assert_eq!(fields.len(), 3);
2320                assert!(!struct_plan.has_flatten);
2321
2322                // Check field lookup
2323                assert_eq!(struct_plan.field_lookup.find("name", &core), Some(0));
2324                assert_eq!(struct_plan.field_lookup.find("age", &core), Some(1));
2325                assert_eq!(struct_plan.field_lookup.find("email", &core), Some(2));
2326                assert_eq!(struct_plan.field_lookup.find("unknown", &core), None);
2327
2328                // Check field metadata
2329                assert_eq!(fields[0].name, "name");
2330                assert!(fields[0].is_required());
2331
2332                assert_eq!(fields[1].name, "age");
2333                assert!(fields[1].is_required());
2334
2335                assert_eq!(fields[2].name, "email");
2336                assert!(!fields[2].is_required()); // Option has implicit default
2337
2338                // Check child plan for Option field (field index 2 = third child)
2339                let email_node = core.struct_field_node(plan.root(), 2).unwrap();
2340                match &email_node.kind {
2341                    TypePlanNodeKind::Option => {
2342                        // inner should be String (scalar)
2343                        let inner_node = core.option_inner_node(email_node).unwrap();
2344                        match &inner_node.kind {
2345                            TypePlanNodeKind::Scalar => {}
2346                            other => panic!("Expected Scalar for String, got {:?}", other),
2347                        }
2348                    }
2349                    other => panic!("Expected Option, got {:?}", other),
2350                }
2351            }
2352            other => panic!("Expected Struct, got {:?}", other),
2353        }
2354    }
2355
2356    #[test]
2357    fn test_typeplan_enum() {
2358        let plan = TypePlan::<TestEnum>::build().unwrap();
2359        let root = plan.root();
2360        let core = plan.core();
2361
2362        assert_eq!(root.shape, TestEnum::SHAPE);
2363
2364        match &root.kind {
2365            TypePlanNodeKind::Enum(enum_plan) => {
2366                let variants = core.variants(enum_plan.variants);
2367                assert_eq!(enum_plan.num_variants, 3);
2368
2369                // Check variant lookup
2370                assert_eq!(enum_plan.variant_lookup.find("Unit"), Some(0));
2371                assert_eq!(enum_plan.variant_lookup.find("Tuple"), Some(1));
2372                assert_eq!(enum_plan.variant_lookup.find("Struct"), Some(2));
2373                assert_eq!(enum_plan.variant_lookup.find("Unknown"), None);
2374
2375                // Unit variant has no fields
2376                assert!(core.fields(variants[0].fields).is_empty());
2377
2378                // Tuple variant has 1 field
2379                assert_eq!(core.fields(variants[1].fields).len(), 1);
2380
2381                // Struct variant has 1 field
2382                let struct_variant_fields = core.fields(variants[2].fields);
2383                assert_eq!(struct_variant_fields.len(), 1);
2384                assert_eq!(variants[2].field_lookup.find("value", &core), Some(0));
2385            }
2386            other => panic!("Expected Enum, got {:?}", other),
2387        }
2388    }
2389
2390    #[test]
2391    fn test_typeplan_list() {
2392        let plan = TypePlan::<Vec<u32>>::build().unwrap();
2393        let root = plan.root();
2394        let core = plan.core();
2395
2396        match &root.kind {
2397            TypePlanNodeKind::List => {
2398                let item_node = core.list_item_node(plan.root()).unwrap();
2399                match &item_node.kind {
2400                    TypePlanNodeKind::Scalar => {}
2401                    other => panic!("Expected Scalar for u32, got {:?}", other),
2402                }
2403            }
2404            other => panic!("Expected List, got {:?}", other),
2405        }
2406    }
2407
2408    #[test]
2409    fn test_typeplan_recursive() {
2410        // This should NOT stack overflow - arena handles the cycle
2411        let plan = TypePlan::<RecursiveStruct>::build().unwrap();
2412        let root = plan.root();
2413        let core = plan.core();
2414
2415        match &root.kind {
2416            TypePlanNodeKind::Struct(struct_plan) => {
2417                let fields = core.fields(struct_plan.fields);
2418                assert_eq!(fields.len(), 2);
2419                assert_eq!(fields[0].name, "value");
2420                assert_eq!(fields[1].name, "next");
2421
2422                // The 'next' field is Option<Box<RecursiveStruct>>
2423                // Its child plan should eventually contain a BackRef
2424                let next_node = core.struct_field_node(plan.root(), 1).unwrap();
2425
2426                // Should be Option
2427                assert!(matches!(next_node.kind, TypePlanNodeKind::Option));
2428
2429                // Inner should be Pointer (Box)
2430                let inner_node = core.option_inner_node(next_node).unwrap();
2431                assert!(matches!(inner_node.kind, TypePlanNodeKind::Pointer));
2432
2433                // Pointee should be BackRef to root (or a struct with BackRef)
2434                let pointee_node = core.pointer_pointee_node(inner_node).unwrap();
2435
2436                // This should be a BackRef pointing to the root
2437                match &pointee_node.kind {
2438                    TypePlanNodeKind::BackRef(type_id) => {
2439                        // type_id should match the root's type
2440                        assert_eq!(type_id, &plan.root().shape.id);
2441                    }
2442                    _ => panic!(
2443                        "Expected BackRef for recursive type, got {:?}",
2444                        pointee_node.kind
2445                    ),
2446                }
2447            }
2448            other => panic!("Expected Struct, got {:?}", other),
2449        }
2450    }
2451
2452    #[test]
2453    fn test_field_lookup_small() {
2454        let lookup = FieldLookup::Small(smallvec::smallvec![
2455            FieldLookupEntry {
2456                name: "foo",
2457                index: 0,
2458                is_alias: false,
2459            },
2460            FieldLookupEntry {
2461                name: "bar",
2462                index: 1,
2463                is_alias: false,
2464            },
2465            FieldLookupEntry {
2466                name: "baz",
2467                index: 2,
2468                is_alias: false,
2469            },
2470        ]);
2471
2472        assert_eq!(lookup.find_small("foo"), Some(0));
2473        assert_eq!(lookup.find_small("bar"), Some(1));
2474        assert_eq!(lookup.find_small("baz"), Some(2));
2475        assert_eq!(lookup.find_small("qux"), None);
2476    }
2477
2478    #[test]
2479    fn test_variant_lookup_small() {
2480        let lookup = VariantLookup::Small(smallvec::smallvec![("A", 0), ("B", 1), ("C", 2)]);
2481
2482        assert_eq!(lookup.find("A"), Some(0));
2483        assert_eq!(lookup.find("B"), Some(1));
2484        assert_eq!(lookup.find("C"), Some(2));
2485        assert_eq!(lookup.find("D"), None);
2486    }
2487}