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        // Reuse an already-built node when no field-level proxy makes this call
1032        // site distinct. Without this, types reachable via N distinct
1033        // non-cyclic paths are rebuilt N times which explodes combinatorially.
1034        if field_proxies.is_none()
1035            && let Some(&idx) = self.finished.get(&type_id)
1036        {
1037            return Ok(idx);
1038        }
1039
1040        // Check if we're currently building this type (cycle detected)
1041        if self.building.contains(&type_id) {
1042            // Create a BackRef node with just the TypeId - resolved later via lookup
1043            let backref_node = TypePlanNode {
1044                shape,
1045                kind: TypePlanNodeKind::BackRef(type_id),
1046                strategy: DeserStrategy::BackRef {
1047                    target_type_id: type_id,
1048                },
1049                has_default: shape.is(Characteristic::Default),
1050                proxies: ProxyNodes::default(), // BackRefs resolve to target, proxies come from there
1051            };
1052            let idx = self.nodes.alloc(backref_node);
1053            return Ok(idx);
1054        }
1055
1056        // Mark this type as being built (for cycle detection)
1057        self.building.insert(type_id);
1058
1059        // Build proxy nodes for ALL proxies (generic + all format-specific)
1060        let (proxies, has_container_proxy, has_field_proxy) =
1061            self.build_all_proxy_nodes(shape, field_proxies.as_ref())?;
1062
1063        let (kind, children) = self.build_kind(shape)?;
1064
1065        let strategy = self.compute_strategy(
1066            shape,
1067            &kind,
1068            has_container_proxy,
1069            has_field_proxy,
1070            &children,
1071        )?;
1072
1073        // Now allocate the node with final values (no mutation needed!)
1074        let node = TypePlanNode {
1075            shape,
1076            kind,
1077            strategy,
1078            has_default: shape.is(Characteristic::Default),
1079            proxies,
1080        };
1081        let idx = self.nodes.alloc(node);
1082
1083        // Done building - move from building set to finished map
1084        self.building.remove(&type_id);
1085        self.finished.insert(type_id, idx);
1086
1087        Ok(idx)
1088    }
1089
1090    /// Build TypePlan nodes for all proxies on a shape/field.
1091    ///
1092    /// Returns (ProxyNodes, has_container_proxy, has_field_proxy).
1093    fn build_all_proxy_nodes(
1094        &mut self,
1095        shape: &'static Shape,
1096        field_proxies: Option<&FieldProxies>,
1097    ) -> Result<(ProxyNodes, bool, bool), AllocError> {
1098        let mut proxies = ProxyNodes::default();
1099
1100        // Field-level proxies take precedence over container-level
1101        if let Some(fp) = field_proxies {
1102            // Build nodes for field-level proxies
1103            if let Some(generic_proxy) = fp.generic {
1104                proxies.generic = Some(self.build_node(generic_proxy.shape)?);
1105            }
1106            for &(format, proxy_def) in fp.format_specific.iter() {
1107                let node = self.build_node(proxy_def.shape)?;
1108                proxies.format_specific.push((format, node));
1109            }
1110            let has_field_proxy = proxies.has_any();
1111            return Ok((proxies, false, has_field_proxy));
1112        }
1113
1114        // Container-level proxies (from the shape itself)
1115        // Build generic proxy node
1116        if let Some(generic_proxy) = shape.proxy {
1117            proxies.generic = Some(self.build_node(generic_proxy.shape)?);
1118        }
1119
1120        // Build format-specific proxy nodes
1121        for format_proxy in shape.format_proxies.iter() {
1122            let node = self.build_node(format_proxy.proxy.shape)?;
1123            proxies.format_specific.push((format_proxy.format, node));
1124        }
1125
1126        let has_container_proxy = proxies.has_any();
1127        Ok((proxies, has_container_proxy, false))
1128    }
1129
1130    /// Compute the deserialization strategy with all data needed to execute it.
1131    fn compute_strategy(
1132        &self,
1133        shape: &'static Shape,
1134        kind: &TypePlanNodeKind,
1135        has_container_proxy: bool,
1136        has_field_proxy: bool,
1137        children: &[NodeId],
1138    ) -> Result<DeserStrategy, AllocError> {
1139        let nth_child = |n: usize| -> NodeId { children[n] };
1140        let first_child = || children[0];
1141
1142        // Priority 1: Field-level proxy (field has proxy, type doesn't)
1143        if has_field_proxy {
1144            return Ok(DeserStrategy::FieldProxy);
1145        }
1146
1147        // Priority 2: Container-level proxy (type itself has proxy)
1148        if has_container_proxy {
1149            return Ok(DeserStrategy::ContainerProxy);
1150        }
1151
1152        // Priority 3: Smart pointers (Box, Arc, Rc)
1153        if matches!(kind, TypePlanNodeKind::Pointer) {
1154            return Ok(DeserStrategy::Pointer {
1155                pointee_node: first_child(),
1156            });
1157        }
1158
1159        // Priority 4: Metadata containers (like Spanned<T>, Documented<T>)
1160        if shape.is_metadata_container() {
1161            return Ok(DeserStrategy::MetadataContainer);
1162        }
1163
1164        // Priority 5: Types with .inner and try_from (like NonZero<T>)
1165        if shape.inner.is_some()
1166            && shape.vtable.has_try_from()
1167            && !matches!(
1168                &shape.def,
1169                Def::List(_) | Def::Map(_) | Def::Set(_) | Def::Array(_)
1170            )
1171        {
1172            return Ok(DeserStrategy::TransparentConvert {
1173                inner_node: first_child(),
1174            });
1175        }
1176
1177        // Priority 6: Transparent wrappers with try_from
1178        if matches!(kind, TypePlanNodeKind::Transparent) && shape.vtable.has_try_from() {
1179            return Ok(DeserStrategy::TransparentConvert {
1180                inner_node: first_child(),
1181            });
1182        }
1183
1184        // Priority 7: Scalars with FromStr
1185        if matches!(&shape.def, Def::Scalar) && shape.vtable.has_parse() {
1186            return Ok(DeserStrategy::Scalar {
1187                scalar_type: shape.scalar_type(),
1188                is_from_str: shape.vtable.has_parse(),
1189            });
1190        }
1191
1192        // Priority 8: Match on the kind
1193        Ok(match kind {
1194            TypePlanNodeKind::Scalar => {
1195                // Empty tuple has def: Scalar but ty: Struct(Tuple)
1196                if let Type::User(UserType::Struct(struct_def)) = &shape.ty {
1197                    use facet_core::StructKind;
1198                    if matches!(struct_def.kind, StructKind::Tuple | StructKind::TupleStruct) {
1199                        let field_count = struct_def.fields.len();
1200                        return Ok(DeserStrategy::Tuple {
1201                            field_count,
1202                            is_single_field_transparent: field_count == 1 && shape.is_transparent(),
1203                        });
1204                    }
1205                }
1206                DeserStrategy::Scalar {
1207                    scalar_type: shape.scalar_type(),
1208                    is_from_str: shape.vtable.has_parse(),
1209                }
1210            }
1211            TypePlanNodeKind::Struct(struct_plan) => {
1212                use facet_core::StructKind;
1213                match struct_plan.struct_def.kind {
1214                    StructKind::Tuple | StructKind::TupleStruct => {
1215                        let field_count = struct_plan.struct_def.fields.len();
1216                        DeserStrategy::Tuple {
1217                            field_count,
1218                            is_single_field_transparent: field_count == 1 && shape.is_transparent(),
1219                        }
1220                    }
1221                    StructKind::Struct | StructKind::Unit => DeserStrategy::Struct,
1222                }
1223            }
1224            TypePlanNodeKind::Enum(_) => DeserStrategy::Enum,
1225            TypePlanNodeKind::Option => DeserStrategy::Option {
1226                some_node: first_child(),
1227            },
1228            TypePlanNodeKind::Result => DeserStrategy::Result {
1229                ok_node: nth_child(0),
1230                err_node: nth_child(1),
1231            },
1232            TypePlanNodeKind::List | TypePlanNodeKind::Slice => {
1233                // Check if this is Vec<u8> for optimized byte sequence handling
1234                let is_byte_vec = *shape == *<alloc::vec::Vec<u8> as facet_core::Facet>::SHAPE;
1235                DeserStrategy::List {
1236                    item_node: first_child(),
1237                    is_byte_vec,
1238                }
1239            }
1240            TypePlanNodeKind::Map => DeserStrategy::Map {
1241                key_node: nth_child(0),
1242                value_node: nth_child(1),
1243            },
1244            TypePlanNodeKind::Set => DeserStrategy::Set {
1245                item_node: first_child(),
1246            },
1247            TypePlanNodeKind::Array { len } => DeserStrategy::Array {
1248                len: *len,
1249                item_node: first_child(),
1250            },
1251            TypePlanNodeKind::DynamicValue => DeserStrategy::DynamicValue,
1252            TypePlanNodeKind::Pointer => DeserStrategy::Pointer {
1253                pointee_node: first_child(),
1254            },
1255            TypePlanNodeKind::OpaquePointer => DeserStrategy::OpaquePointer,
1256            TypePlanNodeKind::Opaque => DeserStrategy::Opaque,
1257            TypePlanNodeKind::Transparent => {
1258                // Transparent wrapper without try_from - unsupported
1259                return Err(AllocError {
1260                    shape,
1261                    operation: "transparent wrapper requires try_from for deserialization",
1262                });
1263            }
1264            TypePlanNodeKind::BackRef(type_id) => DeserStrategy::BackRef {
1265                target_type_id: *type_id,
1266            },
1267        })
1268    }
1269
1270    /// Build the TypePlanNodeKind for a shape and return child node indices for compute_strategy.
1271    fn build_kind(
1272        &mut self,
1273        shape: &'static Shape,
1274    ) -> Result<(TypePlanNodeKind, Vec<NodeId>), AllocError> {
1275        let mut children = Vec::new();
1276
1277        // Check shape.def first - this tells us the semantic meaning of the type
1278        let kind = match &shape.def {
1279            Def::Scalar => {
1280                // For scalar types with shape.inner (like NonZero<T>), build a child node
1281                // for the inner type. This enables proper TypePlan navigation when
1282                // begin_inner() is called for transparent wrapper deserialization.
1283                if let Some(inner_shape) = shape.inner {
1284                    children.push(self.build_node(inner_shape)?);
1285                }
1286                TypePlanNodeKind::Scalar
1287            }
1288
1289            Def::Option(opt_def) => {
1290                children.push(self.build_node(opt_def.t())?);
1291                TypePlanNodeKind::Option
1292            }
1293
1294            Def::Result(res_def) => {
1295                children.push(self.build_node(res_def.t())?);
1296                children.push(self.build_node(res_def.e())?);
1297                TypePlanNodeKind::Result
1298            }
1299
1300            Def::List(list_def) => {
1301                children.push(self.build_node(list_def.t())?);
1302                TypePlanNodeKind::List
1303            }
1304
1305            Def::Map(map_def) => {
1306                children.push(self.build_node(map_def.k())?);
1307                children.push(self.build_node(map_def.v())?);
1308                TypePlanNodeKind::Map
1309            }
1310
1311            Def::Set(set_def) => {
1312                children.push(self.build_node(set_def.t())?);
1313                TypePlanNodeKind::Set
1314            }
1315
1316            Def::Array(arr_def) => {
1317                children.push(self.build_node(arr_def.t())?);
1318                TypePlanNodeKind::Array { len: arr_def.n }
1319            }
1320
1321            Def::Pointer(ptr_def) => {
1322                if let Some(pointee) = ptr_def.pointee() {
1323                    children.push(self.build_node(pointee)?);
1324                    TypePlanNodeKind::Pointer
1325                } else {
1326                    // Opaque pointer - no pointee shape available
1327                    TypePlanNodeKind::OpaquePointer
1328                }
1329            }
1330
1331            Def::DynamicValue(_) => TypePlanNodeKind::DynamicValue,
1332
1333            _ => {
1334                // Check Type for struct/enum/slice - these have Def::Undefined but meaningful ty
1335                match &shape.ty {
1336                    Type::User(UserType::Struct(struct_type)) => {
1337                        let struct_plan = self.build_struct_plan(shape, struct_type)?;
1338                        // Struct fields store their NodeIds in FieldPlan, no children needed
1339                        return Ok((TypePlanNodeKind::Struct(struct_plan), Vec::new()));
1340                    }
1341                    Type::User(UserType::Enum(enum_type)) => {
1342                        // Enum variants store their NodeIds in VariantPlanMeta, no children needed
1343                        TypePlanNodeKind::Enum(self.build_enum_plan(enum_type)?)
1344                    }
1345                    // Handle slices like lists - they have an element type
1346                    Type::Sequence(SequenceType::Slice(slice_type)) => {
1347                        children.push(self.build_node(slice_type.t)?);
1348                        // Use Slice kind so we can distinguish from List if needed
1349                        TypePlanNodeKind::Slice
1350                    }
1351                    // Opaque types with builder_shape + try_from (like Yoke):
1352                    // build the builder_shape as a child so TransparentConvert can
1353                    // deserialize the cart then try_from it into the opaque type
1354                    Type::User(UserType::Opaque) | Type::Undefined
1355                        if shape.builder_shape.is_some() && shape.vtable.has_try_from() =>
1356                    {
1357                        children.push(self.build_node(shape.builder_shape.unwrap())?);
1358                        TypePlanNodeKind::Transparent
1359                    }
1360                    // Truly opaque types - no deserialization possible
1361                    Type::User(UserType::Opaque) | Type::Undefined => TypePlanNodeKind::Opaque,
1362                    _ => {
1363                        // Check for transparent wrappers (newtypes) as fallback
1364                        if let Some(inner) = shape.inner {
1365                            children.push(self.build_node(inner)?);
1366                            TypePlanNodeKind::Transparent
1367                        } else {
1368                            return Err(AllocError {
1369                                shape,
1370                                operation: "unsupported type for deserialization",
1371                            });
1372                        }
1373                    }
1374                }
1375            }
1376        };
1377        Ok((kind, children))
1378    }
1379
1380    /// Build a StructPlan with all field plans.
1381    fn build_struct_plan(
1382        &mut self,
1383        shape: &'static Shape,
1384        struct_def: &'static StructType,
1385    ) -> Result<StructPlan, AllocError> {
1386        let mut field_plans = Vec::with_capacity(struct_def.fields.len());
1387
1388        // Check if the container struct has #[facet(default)]
1389        let container_has_default = shape.is(Characteristic::Default);
1390
1391        for (index, field) in struct_def.fields.iter().enumerate() {
1392            // Build the type plan node for this field first
1393            let field_proxies = FieldProxies::from_field(field);
1394            let child_node = self.build_node_with_proxy(field.shape(), field_proxies)?;
1395
1396            // Build validators and fill rule
1397            let validators = self.extract_validators(field);
1398            let fill_rule = Self::determine_fill_rule(field, container_has_default);
1399
1400            // Create unified field plan
1401            field_plans
1402                .push(self.create_field_plan(index, field, child_node, fill_rule, validators));
1403        }
1404
1405        // Allocate fields into arena
1406        let has_flatten = field_plans.iter().any(|f| f.is_flattened);
1407        let fields = self.fields.alloc_extend(field_plans.iter().cloned());
1408
1409        // Build field lookup
1410        let field_lookup = self.build_field_lookup(&field_plans);
1411
1412        // Precompute deny_unknown_fields from shape attributes (avoids runtime attribute scanning)
1413        let deny_unknown_fields = shape.has_deny_unknown_fields_attr();
1414
1415        Ok(StructPlan {
1416            struct_def,
1417            fields,
1418            field_lookup,
1419            has_flatten,
1420            deny_unknown_fields,
1421        })
1422    }
1423
1424    /// Create a FieldPlan from its components.
1425    fn create_field_plan(
1426        &mut self,
1427        index: usize,
1428        field: &'static Field,
1429        type_node: NodeId,
1430        fill_rule: FillRule,
1431        validators: ValidatorRange,
1432    ) -> FieldPlan {
1433        let name = field.name;
1434        let effective_name = field.effective_name();
1435        let alias = field.alias;
1436        let is_flattened = field.is_flattened();
1437
1438        FieldPlan {
1439            // Metadata for matching/lookup
1440            field,
1441            name,
1442            effective_name,
1443            alias,
1444            is_flattened,
1445            type_node,
1446            // Initialization/validation
1447            index,
1448            offset: field.offset,
1449            field_shape: field.shape(),
1450            fill_rule,
1451            validators,
1452        }
1453    }
1454
1455    /// Build a field lookup from field plans.
1456    fn build_field_lookup(&mut self, field_plans: &[FieldPlan]) -> FieldLookup {
1457        let mut entries: Vec<FieldLookupEntry> = Vec::with_capacity(field_plans.len() * 2);
1458
1459        for (index, field_plan) in field_plans.iter().enumerate() {
1460            // Add primary name
1461            entries.push(FieldLookupEntry {
1462                name: field_plan.effective_name,
1463                index,
1464                is_alias: false,
1465            });
1466
1467            // Add alias if present
1468            if let Some(alias) = field_plan.alias {
1469                entries.push(FieldLookupEntry {
1470                    name: alias,
1471                    index,
1472                    is_alias: true,
1473                });
1474            }
1475        }
1476
1477        self.build_field_lookup_from_entries(entries)
1478    }
1479
1480    /// Build lookup structure from entries.
1481    fn build_field_lookup_from_entries(&mut self, entries: Vec<FieldLookupEntry>) -> FieldLookup {
1482        let total_entries = entries.len();
1483        if total_entries <= LOOKUP_THRESHOLD {
1484            return FieldLookup::Small(entries.into_iter().collect());
1485        }
1486
1487        // Choose prefix length: 8 bytes if most keys are long, otherwise 4
1488        let long_key_count = entries.iter().filter(|e| e.name.len() >= 8).count();
1489        let prefix_len = if long_key_count > total_entries / 2 {
1490            8
1491        } else {
1492            4
1493        };
1494
1495        // Group entries by prefix
1496        let mut prefix_map: hashbrown::HashMap<u64, Vec<FieldLookupEntry>> =
1497            hashbrown::HashMap::new();
1498        for entry in entries {
1499            let prefix = compute_prefix(entry.name, prefix_len);
1500            prefix_map.entry(prefix).or_default().push(entry);
1501        }
1502
1503        // Build sorted bucket list and flattened entries
1504        let mut bucket_list: Vec<_> = prefix_map.into_iter().collect();
1505        bucket_list.sort_by_key(|(prefix, _)| *prefix);
1506
1507        let mut all_entries = Vec::with_capacity(total_entries);
1508        let mut bucket_data = Vec::with_capacity(bucket_list.len());
1509
1510        for (prefix, bucket_entries) in bucket_list {
1511            let start = all_entries.len() as u32;
1512            let count = bucket_entries.len() as u32;
1513            bucket_data.push((prefix, start, count));
1514            all_entries.extend(bucket_entries);
1515        }
1516
1517        // Allocate into arenas
1518        let entries_range = self.field_entries.alloc_extend(all_entries);
1519        let buckets_range = self.buckets.alloc_extend(bucket_data);
1520
1521        FieldLookup::PrefixBuckets {
1522            prefix_len,
1523            entries: entries_range,
1524            buckets: buckets_range,
1525        }
1526    }
1527
1528    /// Determine how to fill a field that wasn't set.
1529    fn determine_fill_rule(field: &'static Field, container_has_default: bool) -> FillRule {
1530        let field_shape = field.shape();
1531
1532        // Check for explicit default on the field (#[facet(default)] or #[facet(default = expr)])
1533        if let Some(default_source) = field.default_source() {
1534            let field_default = match default_source {
1535                DefaultSource::Custom(f) => FieldDefault::Custom(*f),
1536                DefaultSource::FromTrait => FieldDefault::FromTrait(field_shape),
1537            };
1538            return FillRule::Defaultable(field_default);
1539        }
1540
1541        // Option<T> without explicit default implicitly defaults to None
1542        let is_option = matches!(field_shape.def, Def::Option(_));
1543        if is_option && field_shape.is(Characteristic::Default) {
1544            return FillRule::Defaultable(FieldDefault::FromTrait(field_shape));
1545        }
1546
1547        // Skipped fields MUST have a default (they're never deserialized)
1548        if field.should_skip_deserializing() && field_shape.is(Characteristic::Default) {
1549            return FillRule::Defaultable(FieldDefault::FromTrait(field_shape));
1550        }
1551
1552        // Empty structs/tuples (like `()`) are trivially defaultable
1553        if let Type::User(UserType::Struct(struct_type)) = field_shape.ty
1554            && struct_type.fields.is_empty()
1555            && field_shape.is(Characteristic::Default)
1556        {
1557            return FillRule::Defaultable(FieldDefault::FromTrait(field_shape));
1558        }
1559
1560        // If container has #[facet(default)] and the field's type implements Default,
1561        // use the type's Default impl
1562        if container_has_default && field_shape.is(Characteristic::Default) {
1563            return FillRule::Defaultable(FieldDefault::FromTrait(field_shape));
1564        }
1565
1566        // Field is required - must be set during deserialization
1567        FillRule::Required
1568    }
1569
1570    /// Extract validators from field attributes.
1571    fn extract_validators(&mut self, field: &'static Field) -> ValidatorRange {
1572        let mut validators = Vec::new();
1573        let field_shape = field.shape();
1574        // Precompute scalar type once - used by validators that need it
1575        let scalar_type = field_shape.scalar_type();
1576
1577        for attr in field.attributes.iter() {
1578            if attr.ns != Some("validate") {
1579                continue;
1580            }
1581
1582            let kind = match attr.key {
1583                "custom" => {
1584                    // SAFETY: validate::custom attribute stores a ValidatorFn
1585                    let validator_fn = unsafe { *attr.data.ptr().get::<ValidatorFn>() };
1586                    ValidatorKind::Custom(validator_fn)
1587                }
1588                "min" => {
1589                    let limit = *attr
1590                        .get_as::<i64>()
1591                        .expect("validate::min attribute must contain i64");
1592                    let scalar_type =
1593                        scalar_type.expect("validate::min requires numeric field type");
1594                    ValidatorKind::Min { limit, scalar_type }
1595                }
1596                "max" => {
1597                    let limit = *attr
1598                        .get_as::<i64>()
1599                        .expect("validate::max attribute must contain i64");
1600                    let scalar_type =
1601                        scalar_type.expect("validate::max requires numeric field type");
1602                    ValidatorKind::Max { limit, scalar_type }
1603                }
1604                "min_length" => {
1605                    let limit = *attr
1606                        .get_as::<usize>()
1607                        .expect("validate::min_length attribute must contain usize");
1608                    let scalar_type =
1609                        scalar_type.expect("validate::min_length requires string field type");
1610                    ValidatorKind::MinLength { limit, scalar_type }
1611                }
1612                "max_length" => {
1613                    let limit = *attr
1614                        .get_as::<usize>()
1615                        .expect("validate::max_length attribute must contain usize");
1616                    let scalar_type =
1617                        scalar_type.expect("validate::max_length requires string field type");
1618                    ValidatorKind::MaxLength { limit, scalar_type }
1619                }
1620                "email" => {
1621                    let scalar_type =
1622                        scalar_type.expect("validate::email requires string field type");
1623                    ValidatorKind::Email { scalar_type }
1624                }
1625                "url" => {
1626                    let scalar_type =
1627                        scalar_type.expect("validate::url requires string field type");
1628                    ValidatorKind::Url { scalar_type }
1629                }
1630                "regex" => {
1631                    let pattern = *attr
1632                        .get_as::<&'static str>()
1633                        .expect("validate::regex attribute must contain &'static str");
1634                    let scalar_type =
1635                        scalar_type.expect("validate::regex requires string field type");
1636                    ValidatorKind::Regex {
1637                        pattern,
1638                        scalar_type,
1639                    }
1640                }
1641                "contains" => {
1642                    let needle = *attr
1643                        .get_as::<&'static str>()
1644                        .expect("validate::contains attribute must contain &'static str");
1645                    let scalar_type =
1646                        scalar_type.expect("validate::contains requires string field type");
1647                    ValidatorKind::Contains {
1648                        needle,
1649                        scalar_type,
1650                    }
1651                }
1652                _ => continue, // Unknown validator, skip
1653            };
1654
1655            validators.push(PrecomputedValidator { kind });
1656        }
1657
1658        self.validators.alloc_extend(validators)
1659    }
1660
1661    /// Build an EnumPlan with all field plans for each variant.
1662    fn build_enum_plan(&mut self, enum_def: &'static EnumType) -> Result<EnumPlan, AllocError> {
1663        let mut variant_metas = Vec::with_capacity(enum_def.variants.len());
1664
1665        for variant in enum_def.variants.iter() {
1666            let mut field_plans = Vec::with_capacity(variant.data.fields.len());
1667
1668            for (index, field) in variant.data.fields.iter().enumerate() {
1669                // Build the type plan node for this field
1670                let field_proxies = FieldProxies::from_field(field);
1671                let child_node = self.build_node_with_proxy(field.shape(), field_proxies)?;
1672
1673                // Build validators and fill rule (enums don't have container-level default)
1674                let validators = self.extract_validators(field);
1675                let fill_rule = Self::determine_fill_rule(field, false);
1676
1677                // Create unified field plan
1678                field_plans
1679                    .push(self.create_field_plan(index, field, child_node, fill_rule, validators));
1680            }
1681
1682            let has_flatten = field_plans.iter().any(|f| f.is_flattened);
1683            let fields = self.fields.alloc_extend(field_plans.iter().cloned());
1684            let field_lookup = self.build_field_lookup(&field_plans);
1685
1686            variant_metas.push(VariantPlanMeta {
1687                variant,
1688                name: variant.effective_name(),
1689                fields,
1690                field_lookup,
1691                has_flatten,
1692            });
1693        }
1694
1695        let variants = self.variants.alloc_extend(variant_metas.iter().cloned());
1696        let variant_lookup = self.build_variant_lookup(&variant_metas);
1697        let num_variants = variant_metas.len();
1698
1699        // Find the index of the #[facet(other)] variant, if any
1700        let other_variant_idx = variant_metas.iter().position(|v| v.variant.is_other());
1701
1702        Ok(EnumPlan {
1703            enum_def,
1704            variants,
1705            variant_lookup,
1706            num_variants,
1707            other_variant_idx,
1708        })
1709    }
1710
1711    /// Build a variant lookup from variant metadata.
1712    ///
1713    /// Note: `#[facet(other)]` variants are excluded from the lookup because they
1714    /// should only be used as a fallback when no other variant matches. Including
1715    /// them would cause serialized `#[facet(other)]` values to deserialize via
1716    /// the normal path instead of the fallback path.
1717    fn build_variant_lookup(&self, variants: &[VariantPlanMeta]) -> VariantLookup {
1718        let entries: Vec<_> = variants
1719            .iter()
1720            .enumerate()
1721            .filter(|(_, v)| !v.variant.is_other())
1722            .map(|(i, v)| (v.name, i))
1723            .collect();
1724
1725        if entries.len() <= LOOKUP_THRESHOLD {
1726            VariantLookup::Small(entries.into_iter().collect())
1727        } else {
1728            let mut sorted = entries;
1729            sorted.sort_by_key(|(name, _)| *name);
1730            VariantLookup::Sorted(sorted)
1731        }
1732    }
1733}
1734
1735impl<'facet, T: facet_core::Facet<'facet> + ?Sized> TypePlan<T> {
1736    /// Build a TypePlan for type `T`.
1737    ///
1738    /// The type parameter provides compile-time safety: you cannot accidentally
1739    /// pass a `TypePlan<Foo>` where `TypePlan<Bar>` is expected.
1740    ///
1741    /// Note: TypePlan can be built for any `Facet<'_>` type because the `SHAPE`
1742    /// is always `'static`. The lifetime parameter on `Facet` only affects the
1743    /// runtime deserialized values, not the type metadata.
1744    ///
1745    /// # Example
1746    ///
1747    /// ```ignore
1748    /// use facet_reflect::TypePlan;
1749    ///
1750    /// let plan = TypePlan::<MyStruct>::build()?;
1751    /// ```
1752    pub fn build() -> Result<Self, AllocError> {
1753        // SAFETY: T::SHAPE comes from Facet metadata for a real type T.
1754        let core = unsafe { TypePlanCore::from_shape(T::SHAPE)? };
1755
1756        Ok(TypePlan {
1757            core,
1758            _marker: core::marker::PhantomData,
1759        })
1760    }
1761
1762    /// Build a TypePlan with format-specific proxy resolution.
1763    ///
1764    /// **Deprecated**: Format namespace is no longer needed at build time.
1765    /// TypePlan now stores proxy nodes for all formats, and the format-specific
1766    /// proxy is selected at runtime during deserialization.
1767    ///
1768    /// This method is kept for API compatibility but is equivalent to `build()`.
1769    #[deprecated(
1770        since = "0.44.0",
1771        note = "format namespace no longer needed at build time; use build() instead"
1772    )]
1773    pub fn build_for_format(_format_namespace: Option<&'static str>) -> Result<Self, AllocError> {
1774        Self::build()
1775    }
1776
1777    /// Get a reference to the internal core.
1778    #[inline]
1779    pub fn core(&self) -> Arc<TypePlanCore> {
1780        self.core.clone()
1781    }
1782
1783    /// Get the root node.
1784    #[inline]
1785    pub fn root(&self) -> &TypePlanNode {
1786        self.core.root()
1787    }
1788}
1789
1790impl TypePlanCore {
1791    /// Build a TypePlanCore directly from a shape, with process-global caching.
1792    ///
1793    /// Under `std`, one plan is cached per unique shape (`&'static Shape`) for
1794    /// the lifetime of the process. In `no_std`, this builds a fresh plan each call.
1795    ///
1796    /// # Safety
1797    ///
1798    /// The caller must ensure that the shape is valid and corresponds to a real type.
1799    /// Using an incorrect or maliciously crafted shape can lead to undefined behavior
1800    /// when materializing values.
1801    pub unsafe fn from_shape(shape: &'static Shape) -> Result<Arc<Self>, AllocError> {
1802        #[cfg(feature = "std")]
1803        {
1804            let mut guard = type_plan_cache()
1805                .lock()
1806                .unwrap_or_else(|poison| poison.into_inner());
1807
1808            if let Some(plan) = guard.get(&shape) {
1809                return Ok(Arc::clone(plan));
1810            }
1811
1812            // SAFETY: caller guarantees the shape is valid.
1813            let plan = unsafe { Self::build_uncached(shape)? };
1814            guard.insert(shape, Arc::clone(&plan));
1815            Ok(plan)
1816        }
1817
1818        #[cfg(not(feature = "std"))]
1819        {
1820            // SAFETY: caller guarantees the shape is valid.
1821            unsafe { Self::build_uncached(shape) }
1822        }
1823    }
1824
1825    /// Build a TypePlanCore from a shape without touching the global cache.
1826    ///
1827    /// # Safety
1828    ///
1829    /// Same safety contract as [`Self::from_shape`].
1830    unsafe fn build_uncached(shape: &'static Shape) -> Result<Arc<Self>, AllocError> {
1831        let mut builder = TypePlanBuilder::new();
1832        let root = builder.build_node(shape)?;
1833        Ok(Arc::new(builder.finish(root)))
1834    }
1835
1836    /// Get the root node.
1837    #[inline]
1838    pub fn root(&self) -> &TypePlanNode {
1839        self.node(self.root)
1840    }
1841
1842    /// Get the root node index.
1843    #[inline]
1844    pub fn root_id(&self) -> NodeId {
1845        self.root
1846    }
1847
1848    /// Get a node by its index.
1849    #[inline]
1850    pub fn node(&self, idx: NodeId) -> &TypePlanNode {
1851        self.nodes.get(idx)
1852    }
1853
1854    /// Get a field by its index.
1855    #[inline]
1856    pub fn field(&self, idx: Idx<FieldPlan>) -> &FieldPlan {
1857        self.fields.get(idx)
1858    }
1859
1860    /// Get a slice of fields from a range.
1861    #[inline]
1862    pub fn fields(&self, range: FieldRange) -> &[FieldPlan] {
1863        self.fields.get_slice(range)
1864    }
1865
1866    /// Get a variant by its index.
1867    #[inline]
1868    pub fn variant(&self, idx: Idx<VariantPlanMeta>) -> &VariantPlanMeta {
1869        self.variants.get(idx)
1870    }
1871
1872    /// Get a slice of variants from a range.
1873    #[inline]
1874    pub fn variants(&self, range: VariantRange) -> &[VariantPlanMeta] {
1875        self.variants.get_slice(range)
1876    }
1877
1878    /// Get a slice of validators from a range.
1879    #[inline]
1880    pub fn validators(&self, range: ValidatorRange) -> &[PrecomputedValidator] {
1881        self.validators.get_slice(range)
1882    }
1883
1884    /// Look up a node by TypeId using binary search on the sorted lookup table.
1885    #[inline]
1886    fn lookup_node(&self, type_id: &ConstTypeId) -> Option<NodeId> {
1887        let idx = self
1888            .node_lookup
1889            .binary_search_by_key(type_id, |(id, _)| *id)
1890            .ok()?;
1891        Some(self.node_lookup[idx].1)
1892    }
1893
1894    // Navigation helpers
1895
1896    /// Get the child node for a struct field by index.
1897    /// Follows BackRef nodes for recursive types.
1898    #[inline]
1899    pub fn struct_field_node(&self, parent: &TypePlanNode, idx: usize) -> Option<&TypePlanNode> {
1900        let resolved = self.resolve_backref(parent);
1901        let struct_plan = match &resolved.kind {
1902            TypePlanNodeKind::Struct(p) => p,
1903            _ => return None,
1904        };
1905        let fields = self.fields(struct_plan.fields);
1906        Some(self.node(fields.get(idx)?.type_node))
1907    }
1908
1909    /// Get the child node for an enum variant's field.
1910    /// Follows BackRef nodes for recursive types.
1911    #[inline]
1912    pub fn enum_variant_field_node(
1913        &self,
1914        parent: &TypePlanNode,
1915        variant_idx: usize,
1916        field_idx: usize,
1917    ) -> Option<&TypePlanNode> {
1918        let resolved = self.resolve_backref(parent);
1919        let enum_plan = match &resolved.kind {
1920            TypePlanNodeKind::Enum(p) => p,
1921            _ => return None,
1922        };
1923        let variants = self.variants(enum_plan.variants);
1924        let variant = variants.get(variant_idx)?;
1925        let fields = self.fields(variant.fields);
1926        Some(self.node(fields.get(field_idx)?.type_node))
1927    }
1928
1929    /// Get the child node for list/array items.
1930    #[inline]
1931    pub fn list_item_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1932        match &parent.strategy {
1933            DeserStrategy::List { item_node, .. } | DeserStrategy::Array { item_node, .. } => {
1934                Some(self.node(*item_node))
1935            }
1936            DeserStrategy::BackRef { target_type_id } => {
1937                let target = self.lookup_node(target_type_id)?;
1938                self.list_item_node(self.node(target))
1939            }
1940            _ => None,
1941        }
1942    }
1943
1944    /// Get the child node for set items.
1945    #[inline]
1946    pub fn set_item_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1947        match &parent.strategy {
1948            DeserStrategy::Set { item_node } => Some(self.node(*item_node)),
1949            DeserStrategy::BackRef { target_type_id } => {
1950                let target = self.lookup_node(target_type_id)?;
1951                self.set_item_node(self.node(target))
1952            }
1953            _ => None,
1954        }
1955    }
1956
1957    /// Get the child node for map keys.
1958    #[inline]
1959    pub fn map_key_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1960        match &parent.strategy {
1961            DeserStrategy::Map { key_node, .. } => Some(self.node(*key_node)),
1962            DeserStrategy::BackRef { target_type_id } => {
1963                let target = self.lookup_node(target_type_id)?;
1964                self.map_key_node(self.node(target))
1965            }
1966            _ => None,
1967        }
1968    }
1969
1970    /// Get the child node for map values.
1971    #[inline]
1972    pub fn map_value_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1973        match &parent.strategy {
1974            DeserStrategy::Map { value_node, .. } => Some(self.node(*value_node)),
1975            DeserStrategy::BackRef { target_type_id } => {
1976                let target = self.lookup_node(target_type_id)?;
1977                self.map_value_node(self.node(target))
1978            }
1979            _ => None,
1980        }
1981    }
1982
1983    /// Get the child node for Option inner type.
1984    #[inline]
1985    pub fn option_inner_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1986        match &parent.strategy {
1987            DeserStrategy::Option { some_node } => Some(self.node(*some_node)),
1988            DeserStrategy::BackRef { target_type_id } => {
1989                let target = self.lookup_node(target_type_id)?;
1990                self.option_inner_node(self.node(target))
1991            }
1992            _ => None,
1993        }
1994    }
1995
1996    /// Get the child node for Result Ok type.
1997    #[inline]
1998    pub fn result_ok_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
1999        match &parent.strategy {
2000            DeserStrategy::Result { ok_node, .. } => Some(self.node(*ok_node)),
2001            DeserStrategy::BackRef { target_type_id } => {
2002                let target = self.lookup_node(target_type_id)?;
2003                self.result_ok_node(self.node(target))
2004            }
2005            _ => None,
2006        }
2007    }
2008
2009    /// Get the child node for Result Err type.
2010    #[inline]
2011    pub fn result_err_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
2012        match &parent.strategy {
2013            DeserStrategy::Result { err_node, .. } => Some(self.node(*err_node)),
2014            DeserStrategy::BackRef { target_type_id } => {
2015                let target = self.lookup_node(target_type_id)?;
2016                self.result_err_node(self.node(target))
2017            }
2018            _ => None,
2019        }
2020    }
2021
2022    /// Get the child node for pointer pointee.
2023    #[inline]
2024    pub fn pointer_pointee_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
2025        match &parent.strategy {
2026            DeserStrategy::Pointer { pointee_node } => Some(self.node(*pointee_node)),
2027            DeserStrategy::BackRef { target_type_id } => {
2028                let target = self.lookup_node(target_type_id)?;
2029                self.pointer_pointee_node(self.node(target))
2030            }
2031            _ => None,
2032        }
2033    }
2034
2035    /// Get the child node for shape.inner navigation (used by begin_inner).
2036    #[inline]
2037    pub fn inner_node(&self, parent: &TypePlanNode) -> Option<&TypePlanNode> {
2038        if parent.shape.inner.is_some() {
2039            match &parent.strategy {
2040                DeserStrategy::TransparentConvert { inner_node } => Some(self.node(*inner_node)),
2041                _ => None,
2042            }
2043        } else {
2044            None
2045        }
2046    }
2047
2048    /// Resolve a BackRef to get the actual node it points to.
2049    #[inline]
2050    pub fn resolve_backref<'a>(&'a self, node: &'a TypePlanNode) -> &'a TypePlanNode {
2051        match &node.kind {
2052            TypePlanNodeKind::BackRef(type_id) => self.node(
2053                self.lookup_node(type_id)
2054                    .expect("BackRef target must exist in node_lookup"),
2055            ),
2056            _ => node,
2057        }
2058    }
2059
2060    /// Get the StructPlan if a node is a struct type.
2061    /// Follows BackRef nodes for recursive types.
2062    #[inline]
2063    pub fn as_struct_plan<'a>(&'a self, node: &'a TypePlanNode) -> Option<&'a StructPlan> {
2064        let resolved = self.resolve_backref(node);
2065        match &resolved.kind {
2066            TypePlanNodeKind::Struct(plan) => Some(plan),
2067            _ => None,
2068        }
2069    }
2070
2071    /// Get the EnumPlan if a node is an enum type.
2072    /// Follows BackRef nodes for recursive types.
2073    #[inline]
2074    pub fn as_enum_plan<'a>(&'a self, node: &'a TypePlanNode) -> Option<&'a EnumPlan> {
2075        let resolved = self.resolve_backref(node);
2076        match &resolved.kind {
2077            TypePlanNodeKind::Enum(plan) => Some(plan),
2078            _ => None,
2079        }
2080    }
2081
2082    /// Resolve a BackRef (by node ID) to get the actual node it points to.
2083    #[inline]
2084    pub fn resolve_backref_id(&self, node_id: NodeId) -> &TypePlanNode {
2085        let node = self.node(node_id);
2086        self.resolve_backref(node)
2087    }
2088
2089    /// Get the StructPlan for a node ID, if it's a struct type.
2090    /// Follows BackRef nodes for recursive types.
2091    #[inline]
2092    pub fn struct_plan_by_id(&self, node_id: NodeId) -> Option<&StructPlan> {
2093        self.as_struct_plan(self.node(node_id))
2094    }
2095
2096    /// Get the EnumPlan for a node ID, if it's an enum type.
2097    /// Follows BackRef nodes for recursive types.
2098    #[inline]
2099    pub fn enum_plan_by_id(&self, node_id: NodeId) -> Option<&EnumPlan> {
2100        self.as_enum_plan(self.node(node_id))
2101    }
2102
2103    // Navigation helpers that work with NodeId (returning NodeId for child nodes)
2104
2105    /// Get the child node ID for a struct field by index.
2106    /// Follows BackRef nodes for recursive types.
2107    #[inline]
2108    pub fn struct_field_node_id(&self, parent_id: NodeId, idx: usize) -> Option<NodeId> {
2109        let parent = self.node(parent_id);
2110        let resolved = self.resolve_backref(parent);
2111        let struct_plan = match &resolved.kind {
2112            TypePlanNodeKind::Struct(p) => p,
2113            _ => return None,
2114        };
2115        let fields = self.fields(struct_plan.fields);
2116        Some(fields.get(idx)?.type_node)
2117    }
2118
2119    /// Get the child node ID for an enum variant's field.
2120    /// Follows BackRef nodes for recursive types.
2121    #[inline]
2122    pub fn enum_variant_field_node_id(
2123        &self,
2124        parent_id: NodeId,
2125        variant_idx: usize,
2126        field_idx: usize,
2127    ) -> Option<NodeId> {
2128        let parent = self.node(parent_id);
2129        let resolved = self.resolve_backref(parent);
2130        let enum_plan = match &resolved.kind {
2131            TypePlanNodeKind::Enum(p) => p,
2132            _ => return None,
2133        };
2134        let variants = self.variants(enum_plan.variants);
2135        let variant = variants.get(variant_idx)?;
2136        let fields = self.fields(variant.fields);
2137        Some(fields.get(field_idx)?.type_node)
2138    }
2139
2140    /// Get the child node ID for list/array items.
2141    #[inline]
2142    pub fn list_item_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2143        let parent = self.node(parent_id);
2144        match &parent.strategy {
2145            DeserStrategy::List { item_node, .. } | DeserStrategy::Array { item_node, .. } => {
2146                Some(*item_node)
2147            }
2148            DeserStrategy::BackRef { target_type_id } => {
2149                let target = self.lookup_node(target_type_id)?;
2150                self.list_item_node_id(target)
2151            }
2152            _ => None,
2153        }
2154    }
2155
2156    /// Get the child node ID for set items.
2157    #[inline]
2158    pub fn set_item_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2159        let parent = self.node(parent_id);
2160        match &parent.strategy {
2161            DeserStrategy::Set { item_node } => Some(*item_node),
2162            DeserStrategy::BackRef { target_type_id } => {
2163                let target = self.lookup_node(target_type_id)?;
2164                self.set_item_node_id(target)
2165            }
2166            _ => None,
2167        }
2168    }
2169
2170    /// Get the child node ID for map keys.
2171    #[inline]
2172    pub fn map_key_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2173        let parent = self.node(parent_id);
2174        match &parent.strategy {
2175            DeserStrategy::Map { key_node, .. } => Some(*key_node),
2176            DeserStrategy::BackRef { target_type_id } => {
2177                let target = self.lookup_node(target_type_id)?;
2178                self.map_key_node_id(target)
2179            }
2180            _ => None,
2181        }
2182    }
2183
2184    /// Get the child node ID for map values.
2185    #[inline]
2186    pub fn map_value_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2187        let parent = self.node(parent_id);
2188        match &parent.strategy {
2189            DeserStrategy::Map { value_node, .. } => Some(*value_node),
2190            DeserStrategy::BackRef { target_type_id } => {
2191                let target = self.lookup_node(target_type_id)?;
2192                self.map_value_node_id(target)
2193            }
2194            _ => None,
2195        }
2196    }
2197
2198    /// Get the child node ID for Option's Some variant.
2199    #[inline]
2200    pub fn option_some_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2201        let parent = self.node(parent_id);
2202        match &parent.strategy {
2203            DeserStrategy::Option { some_node, .. } => Some(*some_node),
2204            DeserStrategy::BackRef { target_type_id } => {
2205                let target = self.lookup_node(target_type_id)?;
2206                self.option_some_node_id(target)
2207            }
2208            _ => None,
2209        }
2210    }
2211
2212    /// Get the child node IDs for Result's Ok and Err variants.
2213    #[inline]
2214    pub fn result_nodes_id(&self, parent_id: NodeId) -> Option<(NodeId, NodeId)> {
2215        let parent = self.node(parent_id);
2216        match &parent.strategy {
2217            DeserStrategy::Result {
2218                ok_node, err_node, ..
2219            } => Some((*ok_node, *err_node)),
2220            DeserStrategy::BackRef { target_type_id } => {
2221                let target = self.lookup_node(target_type_id)?;
2222                self.result_nodes_id(target)
2223            }
2224            _ => None,
2225        }
2226    }
2227
2228    /// Get the child node ID for smart pointer inner type.
2229    #[inline]
2230    pub fn pointer_inner_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2231        let parent = self.node(parent_id);
2232        match &parent.strategy {
2233            DeserStrategy::Pointer { pointee_node, .. } => Some(*pointee_node),
2234            DeserStrategy::BackRef { target_type_id } => {
2235                let target = self.lookup_node(target_type_id)?;
2236                self.pointer_inner_node_id(target)
2237            }
2238            _ => None,
2239        }
2240    }
2241
2242    /// Get the child node ID for transparent convert inner type.
2243    #[inline]
2244    pub fn inner_node_id(&self, parent_id: NodeId) -> Option<NodeId> {
2245        let parent = self.node(parent_id);
2246        if parent.shape.inner.is_some() {
2247            match &parent.strategy {
2248                DeserStrategy::TransparentConvert { inner_node } => Some(*inner_node),
2249                _ => None,
2250            }
2251        } else {
2252            None
2253        }
2254    }
2255
2256    pub(crate) fn empty() -> TypePlanCore {
2257        TypePlanCore {
2258            nodes: Arena::new(),
2259            fields: Arena::new(),
2260            variants: Arena::new(),
2261            validators: Arena::new(),
2262            field_entries: Arena::new(),
2263            buckets: Arena::new(),
2264            node_lookup: Vec::new(),
2265            root: NodeId::new(0),
2266        }
2267    }
2268}
2269
2270#[cfg(test)]
2271mod tests {
2272    use super::*;
2273    use facet::Facet;
2274
2275    #[derive(Facet)]
2276    struct TestStruct {
2277        name: String,
2278        age: u32,
2279        email: Option<String>,
2280    }
2281
2282    #[derive(Facet)]
2283    #[repr(u8)]
2284    #[allow(dead_code)] // Fields used for reflection testing
2285    enum TestEnum {
2286        Unit,
2287        Tuple(u32),
2288        Struct { value: String },
2289    }
2290
2291    #[derive(Facet)]
2292    struct RecursiveStruct {
2293        value: u32,
2294        // Recursive: contains Option<Box<Self>>
2295        next: Option<Box<RecursiveStruct>>,
2296    }
2297
2298    #[test]
2299    fn test_typeplan_build_reuses_cached_core() {
2300        #[derive(Facet)]
2301        struct CacheProbe {
2302            value: u32,
2303        }
2304
2305        let first = TypePlan::<CacheProbe>::build().unwrap().core();
2306        let second = TypePlan::<CacheProbe>::build().unwrap().core();
2307        assert!(Arc::ptr_eq(&first, &second));
2308
2309        // SAFETY: CacheProbe::SHAPE comes from Facet metadata for a real type.
2310        let third =
2311            unsafe { TypePlanCore::from_shape(<CacheProbe as facet_core::Facet<'static>>::SHAPE) }
2312                .unwrap();
2313        assert!(Arc::ptr_eq(&first, &third));
2314    }
2315
2316    #[test]
2317    fn test_typeplan_struct() {
2318        let plan = TypePlan::<TestStruct>::build().unwrap();
2319        let root = plan.root();
2320        let core = plan.core();
2321
2322        assert_eq!(root.shape, TestStruct::SHAPE);
2323        assert!(!root.has_default);
2324
2325        match &root.kind {
2326            TypePlanNodeKind::Struct(struct_plan) => {
2327                let fields = core.fields(struct_plan.fields);
2328                assert_eq!(fields.len(), 3);
2329                assert!(!struct_plan.has_flatten);
2330
2331                // Check field lookup
2332                assert_eq!(struct_plan.field_lookup.find("name", &core), Some(0));
2333                assert_eq!(struct_plan.field_lookup.find("age", &core), Some(1));
2334                assert_eq!(struct_plan.field_lookup.find("email", &core), Some(2));
2335                assert_eq!(struct_plan.field_lookup.find("unknown", &core), None);
2336
2337                // Check field metadata
2338                assert_eq!(fields[0].name, "name");
2339                assert!(fields[0].is_required());
2340
2341                assert_eq!(fields[1].name, "age");
2342                assert!(fields[1].is_required());
2343
2344                assert_eq!(fields[2].name, "email");
2345                assert!(!fields[2].is_required()); // Option has implicit default
2346
2347                // Check child plan for Option field (field index 2 = third child)
2348                let email_node = core.struct_field_node(plan.root(), 2).unwrap();
2349                match &email_node.kind {
2350                    TypePlanNodeKind::Option => {
2351                        // inner should be String (scalar)
2352                        let inner_node = core.option_inner_node(email_node).unwrap();
2353                        match &inner_node.kind {
2354                            TypePlanNodeKind::Scalar => {}
2355                            other => panic!("Expected Scalar for String, got {:?}", other),
2356                        }
2357                    }
2358                    other => panic!("Expected Option, got {:?}", other),
2359                }
2360            }
2361            other => panic!("Expected Struct, got {:?}", other),
2362        }
2363    }
2364
2365    #[test]
2366    fn test_typeplan_enum() {
2367        let plan = TypePlan::<TestEnum>::build().unwrap();
2368        let root = plan.root();
2369        let core = plan.core();
2370
2371        assert_eq!(root.shape, TestEnum::SHAPE);
2372
2373        match &root.kind {
2374            TypePlanNodeKind::Enum(enum_plan) => {
2375                let variants = core.variants(enum_plan.variants);
2376                assert_eq!(enum_plan.num_variants, 3);
2377
2378                // Check variant lookup
2379                assert_eq!(enum_plan.variant_lookup.find("Unit"), Some(0));
2380                assert_eq!(enum_plan.variant_lookup.find("Tuple"), Some(1));
2381                assert_eq!(enum_plan.variant_lookup.find("Struct"), Some(2));
2382                assert_eq!(enum_plan.variant_lookup.find("Unknown"), None);
2383
2384                // Unit variant has no fields
2385                assert!(core.fields(variants[0].fields).is_empty());
2386
2387                // Tuple variant has 1 field
2388                assert_eq!(core.fields(variants[1].fields).len(), 1);
2389
2390                // Struct variant has 1 field
2391                let struct_variant_fields = core.fields(variants[2].fields);
2392                assert_eq!(struct_variant_fields.len(), 1);
2393                assert_eq!(variants[2].field_lookup.find("value", &core), Some(0));
2394            }
2395            other => panic!("Expected Enum, got {:?}", other),
2396        }
2397    }
2398
2399    #[test]
2400    fn test_typeplan_list() {
2401        let plan = TypePlan::<Vec<u32>>::build().unwrap();
2402        let root = plan.root();
2403        let core = plan.core();
2404
2405        match &root.kind {
2406            TypePlanNodeKind::List => {
2407                let item_node = core.list_item_node(plan.root()).unwrap();
2408                match &item_node.kind {
2409                    TypePlanNodeKind::Scalar => {}
2410                    other => panic!("Expected Scalar for u32, got {:?}", other),
2411                }
2412            }
2413            other => panic!("Expected List, got {:?}", other),
2414        }
2415    }
2416
2417    #[test]
2418    fn test_typeplan_recursive() {
2419        // This should NOT stack overflow - arena handles the cycle
2420        let plan = TypePlan::<RecursiveStruct>::build().unwrap();
2421        let root = plan.root();
2422        let core = plan.core();
2423
2424        match &root.kind {
2425            TypePlanNodeKind::Struct(struct_plan) => {
2426                let fields = core.fields(struct_plan.fields);
2427                assert_eq!(fields.len(), 2);
2428                assert_eq!(fields[0].name, "value");
2429                assert_eq!(fields[1].name, "next");
2430
2431                // The 'next' field is Option<Box<RecursiveStruct>>
2432                // Its child plan should eventually contain a BackRef
2433                let next_node = core.struct_field_node(plan.root(), 1).unwrap();
2434
2435                // Should be Option
2436                assert!(matches!(next_node.kind, TypePlanNodeKind::Option));
2437
2438                // Inner should be Pointer (Box)
2439                let inner_node = core.option_inner_node(next_node).unwrap();
2440                assert!(matches!(inner_node.kind, TypePlanNodeKind::Pointer));
2441
2442                // Pointee should be BackRef to root (or a struct with BackRef)
2443                let pointee_node = core.pointer_pointee_node(inner_node).unwrap();
2444
2445                // This should be a BackRef pointing to the root
2446                match &pointee_node.kind {
2447                    TypePlanNodeKind::BackRef(type_id) => {
2448                        // type_id should match the root's type
2449                        assert_eq!(type_id, &plan.root().shape.id);
2450                    }
2451                    _ => panic!(
2452                        "Expected BackRef for recursive type, got {:?}",
2453                        pointee_node.kind
2454                    ),
2455                }
2456            }
2457            other => panic!("Expected Struct, got {:?}", other),
2458        }
2459    }
2460
2461    #[test]
2462    fn test_typeplan_structure_sharing() {
2463        // Make sure that a DAG can't cause exponential type plan node growth
2464        macro_rules! make_ty {
2465            ($name:ident, $subty:ty) => {
2466                #[derive(Facet)]
2467                #[repr(u8)]
2468                #[expect(dead_code)]
2469                enum $name {
2470                    A($subty),
2471                    B($subty),
2472                    C($subty),
2473                    D($subty),
2474                }
2475            };
2476        }
2477        make_ty!(L1, u32);
2478        make_ty!(L2, L1);
2479        make_ty!(L3, L2);
2480        make_ty!(L4, L3);
2481
2482        let plan = TypePlan::<L4>::build().expect("typeplan build");
2483        let core = plan.core();
2484        let node_count = core.nodes.len();
2485        // Node count would be 341 without sharing:
2486        assert_eq!(node_count, 5);
2487    }
2488
2489    #[test]
2490    fn test_field_lookup_small() {
2491        let lookup = FieldLookup::Small(smallvec::smallvec![
2492            FieldLookupEntry {
2493                name: "foo",
2494                index: 0,
2495                is_alias: false,
2496            },
2497            FieldLookupEntry {
2498                name: "bar",
2499                index: 1,
2500                is_alias: false,
2501            },
2502            FieldLookupEntry {
2503                name: "baz",
2504                index: 2,
2505                is_alias: false,
2506            },
2507        ]);
2508
2509        assert_eq!(lookup.find_small("foo"), Some(0));
2510        assert_eq!(lookup.find_small("bar"), Some(1));
2511        assert_eq!(lookup.find_small("baz"), Some(2));
2512        assert_eq!(lookup.find_small("qux"), None);
2513    }
2514
2515    #[test]
2516    fn test_variant_lookup_small() {
2517        let lookup = VariantLookup::Small(smallvec::smallvec![("A", 0), ("B", 1), ("C", 2)]);
2518
2519        assert_eq!(lookup.find("A"), Some(0));
2520        assert_eq!(lookup.find("B"), Some(1));
2521        assert_eq!(lookup.find("C"), Some(2));
2522        assert_eq!(lookup.find("D"), None);
2523    }
2524}