Skip to main content

xsd_schema/types/
builtin.rs

1//! Built-in type registry for XSD types
2//!
3//! This module provides the `BuiltinTypes` struct which contains pre-allocated
4//! `SimpleTypeKey` references for all 50 built-in XSD simple types, plus
5//! the built-in complex `xs:anyType`.
6//!
7//! ## Usage
8//!
9//! Built-in types are initialized when a `SchemaSet` is created and can be
10//! accessed via `schema_set.builtin_types()`.
11//!
12//! ```rust
13//! use xsd_schema::SchemaSet;
14//!
15//! let schema_set = SchemaSet::new();
16//! let string_key = schema_set.builtin_types().string;
17//! ```
18
19use std::collections::HashMap;
20
21use super::{BuiltInType, XmlTypeCode};
22use crate::arenas::{ComplexTypeDefData, SimpleTypeDefData};
23use crate::ids::{AttributeKey, ComplexTypeKey, NameId, SimpleTypeKey, TypeKey};
24use crate::namespace::table::well_known;
25use crate::parser::frames::{
26    ComplexContentDefResult, ComplexContentResult, DerivationMethod, ParticleResult, ParticleTerm,
27    ProcessContents, WildcardNamespace, WildcardResult,
28};
29use crate::schema::model::{SchemaSet, XsdVersion};
30
31/// Well-known built-in type IDs for fast access.
32///
33/// This struct contains `SimpleTypeKey` references for all 50 built-in XSD
34/// simple types. It is initialized when a `SchemaSet` is created.
35///
36/// Types are organized by category:
37/// - Abstract types (anySimpleType, anyAtomicType)
38/// - String types (string, normalizedString, token, etc.)
39/// - Numeric types (boolean, decimal, float, double, integer hierarchy)
40/// - Date/time types (duration, dateTime, date, time, gregorian types)
41/// - Binary types (hexBinary, base64Binary)
42/// - Other types (anyURI, QName, NOTATION)
43/// - List types (NMTOKENS, IDREFS, ENTITIES)
44#[derive(Debug, Clone)]
45pub struct BuiltinTypes {
46    // Complex types
47    /// xs:anyType - the ur-type
48    pub any_type: ComplexTypeKey,
49
50    // Abstract types
51    /// xs:anySimpleType - base of all simple types
52    pub any_simple_type: SimpleTypeKey,
53    /// xs:anyAtomicType - base of all atomic types (XSD 1.1)
54    pub any_atomic_type: Option<SimpleTypeKey>,
55
56    // String types
57    /// xs:string
58    pub string: SimpleTypeKey,
59    /// xs:normalizedString
60    pub normalized_string: SimpleTypeKey,
61    /// xs:token
62    pub token: SimpleTypeKey,
63    /// xs:language
64    pub language: SimpleTypeKey,
65    /// xs:NMTOKEN
66    pub nmtoken: SimpleTypeKey,
67    /// xs:Name
68    pub name: SimpleTypeKey,
69    /// xs:NCName
70    pub ncname: SimpleTypeKey,
71    /// xs:ID
72    pub id: SimpleTypeKey,
73    /// xs:IDREF
74    pub idref: SimpleTypeKey,
75    /// xs:ENTITY
76    pub entity: SimpleTypeKey,
77
78    // Numeric types
79    /// xs:boolean
80    pub boolean: SimpleTypeKey,
81    /// xs:decimal
82    pub decimal: SimpleTypeKey,
83    /// xs:float
84    pub float: SimpleTypeKey,
85    /// xs:double
86    pub double: SimpleTypeKey,
87    /// xs:integer
88    pub integer: SimpleTypeKey,
89    /// xs:nonPositiveInteger
90    pub non_positive_integer: SimpleTypeKey,
91    /// xs:negativeInteger
92    pub negative_integer: SimpleTypeKey,
93    /// xs:long
94    pub long: SimpleTypeKey,
95    /// xs:int
96    pub int: SimpleTypeKey,
97    /// xs:short
98    pub short: SimpleTypeKey,
99    /// xs:byte
100    pub byte: SimpleTypeKey,
101    /// xs:nonNegativeInteger
102    pub non_negative_integer: SimpleTypeKey,
103    /// xs:unsignedLong
104    pub unsigned_long: SimpleTypeKey,
105    /// xs:unsignedInt
106    pub unsigned_int: SimpleTypeKey,
107    /// xs:unsignedShort
108    pub unsigned_short: SimpleTypeKey,
109    /// xs:unsignedByte
110    pub unsigned_byte: SimpleTypeKey,
111    /// xs:positiveInteger
112    pub positive_integer: SimpleTypeKey,
113
114    // Date/time types
115    /// xs:duration
116    pub duration: SimpleTypeKey,
117    /// xs:dateTime
118    pub datetime: SimpleTypeKey,
119    /// xs:time
120    pub time: SimpleTypeKey,
121    /// xs:date
122    pub date: SimpleTypeKey,
123    /// xs:gYearMonth
124    pub g_year_month: SimpleTypeKey,
125    /// xs:gYear
126    pub g_year: SimpleTypeKey,
127    /// xs:gMonthDay
128    pub g_month_day: SimpleTypeKey,
129    /// xs:gDay
130    pub g_day: SimpleTypeKey,
131    /// xs:gMonth
132    pub g_month: SimpleTypeKey,
133
134    // XSD 1.1 date/time additions
135    /// xs:yearMonthDuration (XSD 1.1)
136    pub year_month_duration: Option<SimpleTypeKey>,
137    /// xs:dayTimeDuration (XSD 1.1)
138    pub day_time_duration: Option<SimpleTypeKey>,
139    /// xs:dateTimeStamp (XSD 1.1)
140    pub datetime_stamp: Option<SimpleTypeKey>,
141    /// xs:untypedAtomic (XSD 1.1)
142    pub untyped_atomic: Option<SimpleTypeKey>,
143
144    // XSD 1.1 bottom type
145    /// xs:error - the bottom type (union of no members); has no valid values (XSD 1.1)
146    pub error: Option<SimpleTypeKey>,
147
148    // Binary types
149    /// xs:hexBinary
150    pub hex_binary: SimpleTypeKey,
151    /// xs:base64Binary
152    pub base64_binary: SimpleTypeKey,
153
154    // URI types
155    /// xs:anyURI
156    pub any_uri: SimpleTypeKey,
157
158    /// Anonymous `list(xs:anyURI)` — type of `xsi:schemaLocation` built-in attribute
159    pub xsi_schema_location_type: SimpleTypeKey,
160
161    // QName types
162    /// xs:QName
163    pub qname: SimpleTypeKey,
164    /// xs:NOTATION
165    pub notation: SimpleTypeKey,
166
167    // List types (built-in)
168    /// xs:NMTOKENS
169    pub nmtokens: SimpleTypeKey,
170    /// xs:IDREFS
171    pub idrefs: SimpleTypeKey,
172    /// xs:ENTITIES
173    pub entities: SimpleTypeKey,
174
175    // Lookup maps for fast access
176    /// Map from XmlTypeCode to SimpleTypeKey
177    by_type_code: HashMap<XmlTypeCode, SimpleTypeKey>,
178    /// Reverse map from SimpleTypeKey to XmlTypeCode, so `get_type_code` is O(1).
179    by_key: HashMap<SimpleTypeKey, XmlTypeCode>,
180    /// Map from local name NameId to SimpleTypeKey (for XS namespace)
181    by_local_name: HashMap<NameId, SimpleTypeKey>,
182
183    // Built-in XSI attribute declarations (§3.2.7)
184    /// `xsi:type` built-in attribute declaration
185    pub xsi_type_attr: AttributeKey,
186    /// `xsi:nil` built-in attribute declaration
187    pub xsi_nil_attr: AttributeKey,
188    /// `xsi:schemaLocation` built-in attribute declaration
189    pub xsi_schema_location_attr: AttributeKey,
190    /// `xsi:noNamespaceSchemaLocation` built-in attribute declaration
191    pub xsi_no_namespace_schema_location_attr: AttributeKey,
192}
193
194impl BuiltinTypes {
195    /// Initialize all built-in types and register them in the schema set.
196    ///
197    /// This creates `SimpleTypeDefData` entries in the arenas for all
198    /// 47 XSD 1.0 built-in types (plus 3 additional XSD 1.1 types if
199    /// the version is XSD 1.1).
200    pub fn new(schema_set: &mut SchemaSet) -> Self {
201        let xsd_version = schema_set.xsd_version;
202        let xs_ns = Some(well_known::XS_NAMESPACE);
203
204        let any_type_name = schema_set.name_table.add("anyType");
205        let any_type = schema_set.arenas.alloc_complex_type(ComplexTypeDefData {
206            name: Some(any_type_name),
207            target_namespace: xs_ns,
208            base_type: None,
209            derivation_method: None,
210            content: ComplexContentResult::Complex(ComplexContentDefResult {
211                particle: Some(ParticleResult {
212                    term: ParticleTerm::Any(WildcardResult {
213                        namespace: WildcardNamespace::Any,
214                        process_contents: ProcessContents::Lax,
215                        not_namespace: Vec::new(),
216                        not_qname: Vec::new(),
217                        id: None,
218                        annotation: None,
219                        source: None,
220                    }),
221                    min_occurs: 0,
222                    max_occurs: None,
223                    source: None,
224                }),
225                derivation: DerivationMethod::Restriction,
226                mixed: true,
227                mixed_explicit: true,
228                base_type: None,
229                open_content: None,
230                attributes: Vec::new(),
231                attribute_groups: Vec::new(),
232                attribute_wildcard: Some(WildcardResult {
233                    namespace: WildcardNamespace::Any,
234                    process_contents: ProcessContents::Lax,
235                    not_namespace: Vec::new(),
236                    not_qname: Vec::new(),
237                    id: None,
238                    annotation: None,
239                    source: None,
240                }),
241                assertions: Vec::new(),
242                id: None,
243                derivation_id: None,
244                source: None,
245            }),
246            open_content: None,
247            attributes: Vec::new(),
248            attribute_groups: Vec::new(),
249            attribute_wildcard: None,
250            mixed: true,
251            is_abstract: false,
252            final_derivation: crate::schema::model::DerivationSet::empty(),
253            block: crate::schema::model::DerivationSet::empty(),
254            default_attributes_apply: true,
255            id: None,
256            #[cfg(feature = "xsd11")]
257            assertions: Vec::new(),
258            #[cfg(feature = "xsd11")]
259            xpath_default_namespace: None,
260            annotation: None,
261            source: None,
262            // Resolved references (built-in types have no unresolved references)
263            resolved_base_type: None,
264            resolved_attribute_groups: Vec::new(),
265            resolved_attributes: Vec::new(),
266            resolved_content_particle_types: Vec::new(),
267            resolved_content_particle_elements: Vec::new(),
268            resolved_simple_content_type: None,
269            redefine_original: None,
270        });
271
272        // Helper to create and register a built-in type
273        let mut create_type = |builtin: BuiltInType| -> SimpleTypeKey {
274            let local_name = builtin.local_name();
275            let name_id = schema_set.name_table.add(local_name);
276            let variety = match builtin {
277                BuiltInType::NMTOKENS | BuiltInType::IDREFS | BuiltInType::ENTITIES => {
278                    crate::parser::frames::SimpleTypeVariety::List
279                }
280                BuiltInType::XsError => crate::parser::frames::SimpleTypeVariety::Union,
281                _ => crate::parser::frames::SimpleTypeVariety::Atomic,
282            };
283
284            let data = SimpleTypeDefData {
285                name: Some(name_id),
286                target_namespace: xs_ns,
287                variety,
288                base_type: None,
289                item_type: None,
290                member_types: Vec::new(),
291                facets: crate::types::simple::effective_arena_facets_for_builtin(builtin),
292                final_derivation: crate::schema::model::DerivationSet::empty(),
293                id: None,
294                derivation_id: None,
295                annotation: None,
296                source: None,
297                // Resolved references (built-in types have no unresolved references)
298                resolved_base_type: None,
299                resolved_item_type: None,
300                resolved_member_types: Vec::new(),
301                redefine_original: None,
302                deferred_item_type_error: None,
303            };
304
305            schema_set.arenas.alloc_simple_type(data)
306        };
307
308        // Create all XSD 1.0 types
309        let any_simple_type = create_type(BuiltInType::AnySimpleType);
310        let string = create_type(BuiltInType::String);
311        let normalized_string = create_type(BuiltInType::NormalizedString);
312        let token = create_type(BuiltInType::Token);
313        let language = create_type(BuiltInType::Language);
314        let nmtoken = create_type(BuiltInType::NMTOKEN);
315        let name = create_type(BuiltInType::Name);
316        let ncname = create_type(BuiltInType::NCName);
317        let id = create_type(BuiltInType::ID);
318        let idref = create_type(BuiltInType::IDREF);
319        let entity = create_type(BuiltInType::ENTITY);
320
321        let boolean = create_type(BuiltInType::Boolean);
322        let decimal = create_type(BuiltInType::Decimal);
323        let float = create_type(BuiltInType::Float);
324        let double = create_type(BuiltInType::Double);
325        let integer = create_type(BuiltInType::Integer);
326        let non_positive_integer = create_type(BuiltInType::NonPositiveInteger);
327        let negative_integer = create_type(BuiltInType::NegativeInteger);
328        let long = create_type(BuiltInType::Long);
329        let int = create_type(BuiltInType::Int);
330        let short = create_type(BuiltInType::Short);
331        let byte = create_type(BuiltInType::Byte);
332        let non_negative_integer = create_type(BuiltInType::NonNegativeInteger);
333        let unsigned_long = create_type(BuiltInType::UnsignedLong);
334        let unsigned_int = create_type(BuiltInType::UnsignedInt);
335        let unsigned_short = create_type(BuiltInType::UnsignedShort);
336        let unsigned_byte = create_type(BuiltInType::UnsignedByte);
337        let positive_integer = create_type(BuiltInType::PositiveInteger);
338
339        let duration = create_type(BuiltInType::Duration);
340        let datetime = create_type(BuiltInType::DateTime);
341        let time = create_type(BuiltInType::Time);
342        let date = create_type(BuiltInType::Date);
343        let g_year_month = create_type(BuiltInType::GYearMonth);
344        let g_year = create_type(BuiltInType::GYear);
345        let g_month_day = create_type(BuiltInType::GMonthDay);
346        let g_day = create_type(BuiltInType::GDay);
347        let g_month = create_type(BuiltInType::GMonth);
348
349        let hex_binary = create_type(BuiltInType::HexBinary);
350        let base64_binary = create_type(BuiltInType::Base64Binary);
351
352        let any_uri = create_type(BuiltInType::AnyURI);
353        let qname = create_type(BuiltInType::QName);
354        let notation = create_type(BuiltInType::NOTATION);
355
356        let nmtokens = create_type(BuiltInType::NMTOKENS);
357        let idrefs = create_type(BuiltInType::IDREFS);
358        let entities = create_type(BuiltInType::ENTITIES);
359
360        // XSD 1.1 types (only if XSD 1.1 mode)
361        let (
362            any_atomic_type,
363            untyped_atomic,
364            year_month_duration,
365            day_time_duration,
366            datetime_stamp,
367            error,
368        ) = if xsd_version == XsdVersion::V1_1 {
369            (
370                Some(create_type(BuiltInType::AnyAtomicType)),
371                Some(create_type(BuiltInType::UntypedAtomic)),
372                Some(create_type(BuiltInType::YearMonthDuration)),
373                Some(create_type(BuiltInType::DayTimeDuration)),
374                Some(create_type(BuiltInType::DateTimeStamp)),
375                Some(create_type(BuiltInType::XsError)),
376            )
377        } else {
378            (None, None, None, None, None, None)
379        };
380
381        // Anonymous list(anyURI) for xsi:schemaLocation built-in attribute type.
382        // Created after `create_type` closure is no longer needed.
383        let xsi_schema_location_type = {
384            let data = SimpleTypeDefData {
385                name: None,
386                target_namespace: None,
387                variety: crate::parser::frames::SimpleTypeVariety::List,
388                base_type: None,
389                item_type: None,
390                member_types: Vec::new(),
391                facets: crate::types::facets::FacetSet::new(),
392                final_derivation: crate::schema::model::DerivationSet::empty(),
393                id: None,
394                derivation_id: None,
395                annotation: None,
396                source: None,
397                resolved_base_type: None,
398                resolved_item_type: None,
399                resolved_member_types: Vec::new(),
400                redefine_original: None,
401                deferred_item_type_error: None,
402            };
403            schema_set.arenas.alloc_simple_type(data)
404        };
405
406        // Build lookup maps
407        let mut by_type_code = HashMap::new();
408        let mut by_key = HashMap::new();
409        let mut by_local_name = HashMap::new();
410
411        // Helper to add to lookup maps
412        let mut add_to_maps = |builtin: BuiltInType, key: SimpleTypeKey| {
413            let type_code = builtin.type_code();
414            by_type_code.insert(type_code, key);
415            by_key.insert(key, type_code);
416
417            let local_name = builtin.local_name();
418            let name_id = schema_set.name_table.add(local_name);
419            by_local_name.insert(name_id, key);
420        };
421
422        // Add all types to maps
423        add_to_maps(BuiltInType::AnySimpleType, any_simple_type);
424        add_to_maps(BuiltInType::String, string);
425        add_to_maps(BuiltInType::NormalizedString, normalized_string);
426        add_to_maps(BuiltInType::Token, token);
427        add_to_maps(BuiltInType::Language, language);
428        add_to_maps(BuiltInType::NMTOKEN, nmtoken);
429        add_to_maps(BuiltInType::Name, name);
430        add_to_maps(BuiltInType::NCName, ncname);
431        add_to_maps(BuiltInType::ID, id);
432        add_to_maps(BuiltInType::IDREF, idref);
433        add_to_maps(BuiltInType::ENTITY, entity);
434        add_to_maps(BuiltInType::Boolean, boolean);
435        add_to_maps(BuiltInType::Decimal, decimal);
436        add_to_maps(BuiltInType::Float, float);
437        add_to_maps(BuiltInType::Double, double);
438        add_to_maps(BuiltInType::Integer, integer);
439        add_to_maps(BuiltInType::NonPositiveInteger, non_positive_integer);
440        add_to_maps(BuiltInType::NegativeInteger, negative_integer);
441        add_to_maps(BuiltInType::Long, long);
442        add_to_maps(BuiltInType::Int, int);
443        add_to_maps(BuiltInType::Short, short);
444        add_to_maps(BuiltInType::Byte, byte);
445        add_to_maps(BuiltInType::NonNegativeInteger, non_negative_integer);
446        add_to_maps(BuiltInType::UnsignedLong, unsigned_long);
447        add_to_maps(BuiltInType::UnsignedInt, unsigned_int);
448        add_to_maps(BuiltInType::UnsignedShort, unsigned_short);
449        add_to_maps(BuiltInType::UnsignedByte, unsigned_byte);
450        add_to_maps(BuiltInType::PositiveInteger, positive_integer);
451        add_to_maps(BuiltInType::Duration, duration);
452        add_to_maps(BuiltInType::DateTime, datetime);
453        add_to_maps(BuiltInType::Time, time);
454        add_to_maps(BuiltInType::Date, date);
455        add_to_maps(BuiltInType::GYearMonth, g_year_month);
456        add_to_maps(BuiltInType::GYear, g_year);
457        add_to_maps(BuiltInType::GMonthDay, g_month_day);
458        add_to_maps(BuiltInType::GDay, g_day);
459        add_to_maps(BuiltInType::GMonth, g_month);
460        add_to_maps(BuiltInType::HexBinary, hex_binary);
461        add_to_maps(BuiltInType::Base64Binary, base64_binary);
462        add_to_maps(BuiltInType::AnyURI, any_uri);
463        add_to_maps(BuiltInType::QName, qname);
464        add_to_maps(BuiltInType::NOTATION, notation);
465        add_to_maps(BuiltInType::NMTOKENS, nmtokens);
466        add_to_maps(BuiltInType::IDREFS, idrefs);
467        add_to_maps(BuiltInType::ENTITIES, entities);
468
469        // Add XSD 1.1 types to maps
470        if let Some(key) = any_atomic_type {
471            add_to_maps(BuiltInType::AnyAtomicType, key);
472        }
473        if let Some(key) = untyped_atomic {
474            add_to_maps(BuiltInType::UntypedAtomic, key);
475        }
476        if let Some(key) = year_month_duration {
477            add_to_maps(BuiltInType::YearMonthDuration, key);
478        }
479        if let Some(key) = day_time_duration {
480            add_to_maps(BuiltInType::DayTimeDuration, key);
481        }
482        if let Some(key) = datetime_stamp {
483            add_to_maps(BuiltInType::DateTimeStamp, key);
484        }
485        if let Some(key) = error {
486            add_to_maps(BuiltInType::XsError, key);
487        }
488
489        // Resolve item types for built-in list types so that
490        // validate_list_type can validate each item individually.
491        for (list_key, item_key) in [
492            (nmtokens, nmtoken),
493            (idrefs, idref),
494            (entities, entity),
495            (xsi_schema_location_type, any_uri),
496        ] {
497            if let Some(st) = schema_set.arenas.get_simple_type_mut(list_key) {
498                st.resolved_item_type = Some(TypeKey::Simple(item_key));
499            }
500        }
501
502        // Allocate built-in XSI attribute declarations (§3.2.7)
503        let xsi_ns = Some(well_known::XSI_NAMESPACE);
504        let xsi_type_attr = schema_set
505            .arenas
506            .alloc_attribute(crate::arenas::AttributeDeclData {
507                name: Some(well_known::XSI_TYPE),
508                target_namespace: xsi_ns,
509                ref_name: None,
510                type_ref: None,
511                inline_type: None,
512                default_value: None,
513                fixed_value: None,
514                use_kind: None,
515                form: None,
516                inheritable: false,
517                id: None,
518                annotation: None,
519                source: None,
520                resolved_type: Some(TypeKey::Simple(qname)),
521                resolved_ref: None,
522            });
523        let xsi_nil_attr = schema_set
524            .arenas
525            .alloc_attribute(crate::arenas::AttributeDeclData {
526                name: Some(well_known::XSI_NIL),
527                target_namespace: xsi_ns,
528                ref_name: None,
529                type_ref: None,
530                inline_type: None,
531                default_value: None,
532                fixed_value: None,
533                use_kind: None,
534                form: None,
535                inheritable: false,
536                id: None,
537                annotation: None,
538                source: None,
539                resolved_type: Some(TypeKey::Simple(boolean)),
540                resolved_ref: None,
541            });
542        let xsi_schema_location_attr =
543            schema_set
544                .arenas
545                .alloc_attribute(crate::arenas::AttributeDeclData {
546                    name: Some(well_known::XSI_SCHEMA_LOCATION),
547                    target_namespace: xsi_ns,
548                    ref_name: None,
549                    type_ref: None,
550                    inline_type: None,
551                    default_value: None,
552                    fixed_value: None,
553                    use_kind: None,
554                    form: None,
555                    inheritable: false,
556                    id: None,
557                    annotation: None,
558                    source: None,
559                    resolved_type: Some(TypeKey::Simple(xsi_schema_location_type)),
560                    resolved_ref: None,
561                });
562        let xsi_no_namespace_schema_location_attr =
563            schema_set
564                .arenas
565                .alloc_attribute(crate::arenas::AttributeDeclData {
566                    name: Some(well_known::XSI_NO_NAMESPACE_SCHEMA_LOCATION),
567                    target_namespace: xsi_ns,
568                    ref_name: None,
569                    type_ref: None,
570                    inline_type: None,
571                    default_value: None,
572                    fixed_value: None,
573                    use_kind: None,
574                    form: None,
575                    inheritable: false,
576                    id: None,
577                    annotation: None,
578                    source: None,
579                    resolved_type: Some(TypeKey::Simple(any_uri)),
580                    resolved_ref: None,
581                });
582
583        // Register XSI attribute declarations in the XSI namespace table
584        // so that lookup_attribute(XSI_NAMESPACE, name) finds them.
585        {
586            let xsi_ns_table = schema_set.get_or_create_namespace(Some(well_known::XSI_NAMESPACE));
587            xsi_ns_table
588                .attributes
589                .insert(well_known::XSI_TYPE, xsi_type_attr);
590            xsi_ns_table
591                .attributes
592                .insert(well_known::XSI_NIL, xsi_nil_attr);
593            xsi_ns_table
594                .attributes
595                .insert(well_known::XSI_SCHEMA_LOCATION, xsi_schema_location_attr);
596            xsi_ns_table.attributes.insert(
597                well_known::XSI_NO_NAMESPACE_SCHEMA_LOCATION,
598                xsi_no_namespace_schema_location_attr,
599            );
600        }
601
602        Self {
603            any_type,
604            any_simple_type,
605            any_atomic_type,
606            string,
607            normalized_string,
608            token,
609            language,
610            nmtoken,
611            name,
612            ncname,
613            id,
614            idref,
615            entity,
616            boolean,
617            decimal,
618            float,
619            double,
620            integer,
621            non_positive_integer,
622            negative_integer,
623            long,
624            int,
625            short,
626            byte,
627            non_negative_integer,
628            unsigned_long,
629            unsigned_int,
630            unsigned_short,
631            unsigned_byte,
632            positive_integer,
633            duration,
634            datetime,
635            time,
636            date,
637            g_year_month,
638            g_year,
639            g_month_day,
640            g_day,
641            g_month,
642            year_month_duration,
643            day_time_duration,
644            datetime_stamp,
645            untyped_atomic,
646            error,
647            hex_binary,
648            base64_binary,
649            any_uri,
650            xsi_schema_location_type,
651            qname,
652            notation,
653            nmtokens,
654            idrefs,
655            entities,
656            by_type_code,
657            by_key,
658            by_local_name,
659            xsi_type_attr,
660            xsi_nil_attr,
661            xsi_schema_location_attr,
662            xsi_no_namespace_schema_location_attr,
663        }
664    }
665
666    /// Get a built-in type by its XmlTypeCode.
667    ///
668    /// Returns `None` for node types, AnyType, and other non-simple type codes.
669    pub fn get_by_type_code(&self, code: XmlTypeCode) -> Option<SimpleTypeKey> {
670        self.by_type_code.get(&code).copied()
671    }
672
673    /// Get a built-in type by its local name (within the XS namespace).
674    ///
675    /// The local name must be interned in the NameTable (passed as NameId).
676    pub fn get_by_local_name(&self, name: NameId) -> Option<SimpleTypeKey> {
677        self.by_local_name.get(&name).copied()
678    }
679
680    /// Get the XmlTypeCode for a built-in type key.
681    ///
682    /// Returns `None` if the key is not a built-in type.
683    pub fn get_type_code(&self, key: SimpleTypeKey) -> Option<XmlTypeCode> {
684        self.by_key.get(&key).copied()
685    }
686
687    /// Check if a type key is a built-in type.
688    pub fn is_builtin(&self, key: SimpleTypeKey) -> bool {
689        self.get_type_code(key).is_some()
690    }
691
692    /// True when `key` is the `xs:anyAtomicType` built-in (XSD 1.1 only).
693    #[inline]
694    pub fn is_any_atomic_type(&self, key: SimpleTypeKey) -> bool {
695        self.any_atomic_type == Some(key)
696    }
697
698    /// Get the base type for a built-in type (for derivation hierarchy).
699    ///
700    /// Returns the immediate base type in the XSD type hierarchy.
701    /// Returns `None` for `anySimpleType` (the root of simple types).
702    ///
703    /// In XSD 1.1 mode, primitive atomic types derive from `xs:anyAtomicType`
704    /// per §3.16.7.3; in XSD 1.0 they derive from `xs:anySimpleType`.
705    pub fn get_base_type(&self, key: SimpleTypeKey) -> Option<SimpleTypeKey> {
706        let code = self.get_type_code(key)?;
707        let base_code = get_builtin_base_type(code)?;
708        if base_code == XmlTypeCode::AnySimpleType
709            && code.is_primitive_atomic()
710            && self.any_atomic_type.is_some()
711        {
712            return self.any_atomic_type;
713        }
714        self.get_by_type_code(base_code)
715    }
716
717    /// Check if `derived` derives from `base` (transitively).
718    ///
719    /// Returns `true` if:
720    /// - `derived == base`, or
721    /// - `derived` has `base` somewhere in its derivation chain
722    pub fn derives_from(&self, derived: SimpleTypeKey, base: SimpleTypeKey) -> bool {
723        if derived == base {
724            return true;
725        }
726
727        // Walk up the derivation chain
728        let mut current = derived;
729        while let Some(parent) = self.get_base_type(current) {
730            if parent == base {
731                return true;
732            }
733            current = parent;
734        }
735
736        false
737    }
738
739    /// Returns the number of registered built-in types.
740    ///
741    /// This is 47 for XSD 1.0, or 50+ for XSD 1.1.
742    pub fn count(&self) -> usize {
743        self.by_type_code.len()
744    }
745}
746
747/// Get the base type code for a built-in type.
748///
749/// Returns the immediate parent in the XSD derivation hierarchy.
750fn get_builtin_base_type(code: XmlTypeCode) -> Option<XmlTypeCode> {
751    match code {
752        // anySimpleType has no base (it's the root of simple types)
753        XmlTypeCode::AnySimpleType => None,
754
755        // anyAtomicType derives from anySimpleType
756        XmlTypeCode::AnyAtomicType => Some(XmlTypeCode::AnySimpleType),
757
758        // All primitives derive from anyAtomicType (conceptually)
759        // But for XSD 1.0, they derive from anySimpleType
760        XmlTypeCode::String
761        | XmlTypeCode::Boolean
762        | XmlTypeCode::Decimal
763        | XmlTypeCode::Float
764        | XmlTypeCode::Double
765        | XmlTypeCode::Duration
766        | XmlTypeCode::DateTime
767        | XmlTypeCode::Time
768        | XmlTypeCode::Date
769        | XmlTypeCode::GYearMonth
770        | XmlTypeCode::GYear
771        | XmlTypeCode::GMonthDay
772        | XmlTypeCode::GDay
773        | XmlTypeCode::GMonth
774        | XmlTypeCode::HexBinary
775        | XmlTypeCode::Base64Binary
776        | XmlTypeCode::AnyUri
777        | XmlTypeCode::QName
778        | XmlTypeCode::Notation => Some(XmlTypeCode::AnySimpleType),
779
780        // String-derived types
781        XmlTypeCode::NormalizedString => Some(XmlTypeCode::String),
782        XmlTypeCode::Token => Some(XmlTypeCode::NormalizedString),
783        XmlTypeCode::Language => Some(XmlTypeCode::Token),
784        XmlTypeCode::NmToken => Some(XmlTypeCode::Token),
785        XmlTypeCode::Name => Some(XmlTypeCode::Token),
786        XmlTypeCode::NCName => Some(XmlTypeCode::Name),
787        XmlTypeCode::Id => Some(XmlTypeCode::NCName),
788        XmlTypeCode::IdRef => Some(XmlTypeCode::NCName),
789        XmlTypeCode::Entity => Some(XmlTypeCode::NCName),
790
791        // Decimal-derived types (integer hierarchy)
792        XmlTypeCode::Integer => Some(XmlTypeCode::Decimal),
793        XmlTypeCode::NonPositiveInteger => Some(XmlTypeCode::Integer),
794        XmlTypeCode::NegativeInteger => Some(XmlTypeCode::NonPositiveInteger),
795        XmlTypeCode::Long => Some(XmlTypeCode::Integer),
796        XmlTypeCode::Int => Some(XmlTypeCode::Long),
797        XmlTypeCode::Short => Some(XmlTypeCode::Int),
798        XmlTypeCode::Byte => Some(XmlTypeCode::Short),
799        XmlTypeCode::NonNegativeInteger => Some(XmlTypeCode::Integer),
800        XmlTypeCode::UnsignedLong => Some(XmlTypeCode::NonNegativeInteger),
801        XmlTypeCode::UnsignedInt => Some(XmlTypeCode::UnsignedLong),
802        XmlTypeCode::UnsignedShort => Some(XmlTypeCode::UnsignedInt),
803        XmlTypeCode::UnsignedByte => Some(XmlTypeCode::UnsignedShort),
804        XmlTypeCode::PositiveInteger => Some(XmlTypeCode::NonNegativeInteger),
805
806        // XSD 1.1 types
807        XmlTypeCode::UntypedAtomic => Some(XmlTypeCode::AnyAtomicType),
808        XmlTypeCode::YearMonthDuration => Some(XmlTypeCode::Duration),
809        XmlTypeCode::DayTimeDuration => Some(XmlTypeCode::Duration),
810        XmlTypeCode::DateTimeStamp => Some(XmlTypeCode::DateTime),
811        // xs:error is a union with no members; formally derives from xs:anySimpleType
812        XmlTypeCode::Error => Some(XmlTypeCode::AnySimpleType),
813
814        // List types derive from anySimpleType
815        XmlTypeCode::NmTokens | XmlTypeCode::IdRefs | XmlTypeCode::Entities => {
816            Some(XmlTypeCode::AnySimpleType)
817        }
818
819        // Non-simple types have no base in this hierarchy
820        _ => None,
821    }
822}
823
824#[cfg(test)]
825mod tests {
826    use super::*;
827
828    fn create_test_schema_set() -> SchemaSet {
829        SchemaSet::new()
830    }
831
832    fn create_test_schema_set_v11() -> SchemaSet {
833        SchemaSet::with_version(XsdVersion::V1_1)
834    }
835
836    #[test]
837    fn test_builtin_types_creation() {
838        let mut schema_set = create_test_schema_set();
839        let builtin = BuiltinTypes::new(&mut schema_set);
840
841        assert_eq!(builtin.count(), 45);
842    }
843
844    #[test]
845    fn test_builtin_types_xsd11() {
846        let mut schema_set = create_test_schema_set_v11();
847        let builtin = BuiltinTypes::new(&mut schema_set);
848
849        assert_eq!(builtin.count(), 51);
850
851        // XSD 1.1 types should be present
852        assert!(builtin.any_atomic_type.is_some());
853        assert!(builtin.untyped_atomic.is_some());
854        assert!(builtin.year_month_duration.is_some());
855        assert!(builtin.day_time_duration.is_some());
856        assert!(builtin.datetime_stamp.is_some());
857    }
858
859    #[test]
860    fn test_builtin_types_xsd10_no_xsd11() {
861        let mut schema_set = create_test_schema_set();
862        let builtin = BuiltinTypes::new(&mut schema_set);
863
864        // XSD 1.1 types should not be present in XSD 1.0 mode
865        assert!(builtin.any_atomic_type.is_none());
866        assert!(builtin.untyped_atomic.is_none());
867        assert!(builtin.year_month_duration.is_none());
868        assert!(builtin.day_time_duration.is_none());
869        assert!(builtin.datetime_stamp.is_none());
870    }
871
872    #[test]
873    fn test_get_by_type_code() {
874        let mut schema_set = create_test_schema_set();
875        let builtin = BuiltinTypes::new(&mut schema_set);
876
877        assert_eq!(
878            builtin.get_by_type_code(XmlTypeCode::String),
879            Some(builtin.string)
880        );
881        assert_eq!(
882            builtin.get_by_type_code(XmlTypeCode::Integer),
883            Some(builtin.integer)
884        );
885        assert_eq!(
886            builtin.get_by_type_code(XmlTypeCode::DateTime),
887            Some(builtin.datetime)
888        );
889        assert_eq!(
890            builtin.get_by_type_code(XmlTypeCode::AnySimpleType),
891            Some(builtin.any_simple_type)
892        );
893
894        // Node types should not be found
895        assert!(builtin.get_by_type_code(XmlTypeCode::Element).is_none());
896        assert!(builtin.get_by_type_code(XmlTypeCode::AnyType).is_none());
897    }
898
899    #[test]
900    fn test_get_by_local_name() {
901        let mut schema_set = create_test_schema_set();
902        let builtin = BuiltinTypes::new(&mut schema_set);
903
904        let string_id = schema_set.name_table.add("string");
905        assert_eq!(builtin.get_by_local_name(string_id), Some(builtin.string));
906
907        let integer_id = schema_set.name_table.add("integer");
908        assert_eq!(builtin.get_by_local_name(integer_id), Some(builtin.integer));
909
910        let nonexistent_id = schema_set.name_table.add("nonExistent");
911        assert!(builtin.get_by_local_name(nonexistent_id).is_none());
912    }
913
914    #[test]
915    fn test_get_type_code() {
916        let mut schema_set = create_test_schema_set();
917        let builtin = BuiltinTypes::new(&mut schema_set);
918
919        assert_eq!(
920            builtin.get_type_code(builtin.string),
921            Some(XmlTypeCode::String)
922        );
923        assert_eq!(
924            builtin.get_type_code(builtin.integer),
925            Some(XmlTypeCode::Integer)
926        );
927        assert_eq!(
928            builtin.get_type_code(builtin.any_simple_type),
929            Some(XmlTypeCode::AnySimpleType)
930        );
931    }
932
933    #[test]
934    fn test_is_builtin() {
935        let mut schema_set = create_test_schema_set();
936        let builtin = BuiltinTypes::new(&mut schema_set);
937
938        assert!(builtin.is_builtin(builtin.string));
939        assert!(builtin.is_builtin(builtin.integer));
940        assert!(builtin.is_builtin(builtin.any_simple_type));
941
942        // Create a non-builtin type
943        let custom_type = schema_set.arenas.alloc_simple_type(SimpleTypeDefData {
944            name: Some(NameId(999)),
945            target_namespace: None,
946            variety: crate::parser::frames::SimpleTypeVariety::Atomic,
947            base_type: None,
948            item_type: None,
949            member_types: Vec::new(),
950            facets: crate::types::facets::FacetSet::new(),
951            final_derivation: crate::schema::model::DerivationSet::empty(),
952            id: None,
953            derivation_id: None,
954            annotation: None,
955            source: None,
956            // Resolved references
957            resolved_base_type: None,
958            resolved_item_type: None,
959            resolved_member_types: Vec::new(),
960            redefine_original: None,
961            deferred_item_type_error: None,
962        });
963        assert!(!builtin.is_builtin(custom_type));
964    }
965
966    #[test]
967    fn test_derives_from_same() {
968        let mut schema_set = create_test_schema_set();
969        let builtin = BuiltinTypes::new(&mut schema_set);
970
971        // A type derives from itself
972        assert!(builtin.derives_from(builtin.string, builtin.string));
973        assert!(builtin.derives_from(builtin.integer, builtin.integer));
974    }
975
976    #[test]
977    fn test_derives_from_direct() {
978        let mut schema_set = create_test_schema_set();
979        let builtin = BuiltinTypes::new(&mut schema_set);
980
981        // Direct derivation
982        assert!(builtin.derives_from(builtin.normalized_string, builtin.string));
983        assert!(builtin.derives_from(builtin.integer, builtin.decimal));
984        assert!(builtin.derives_from(builtin.long, builtin.integer));
985    }
986
987    #[test]
988    fn test_derives_from_transitive() {
989        let mut schema_set = create_test_schema_set();
990        let builtin = BuiltinTypes::new(&mut schema_set);
991
992        // Transitive derivation: byte < short < int < long < integer < decimal
993        assert!(builtin.derives_from(builtin.byte, builtin.decimal));
994        assert!(builtin.derives_from(builtin.byte, builtin.integer));
995        assert!(builtin.derives_from(builtin.byte, builtin.long));
996        assert!(builtin.derives_from(builtin.int, builtin.decimal));
997
998        // NCName < Name < token < normalizedString < string
999        assert!(builtin.derives_from(builtin.ncname, builtin.string));
1000        assert!(builtin.derives_from(builtin.id, builtin.string));
1001    }
1002
1003    #[test]
1004    fn test_derives_from_negative() {
1005        let mut schema_set = create_test_schema_set();
1006        let builtin = BuiltinTypes::new(&mut schema_set);
1007
1008        // Not derived
1009        assert!(!builtin.derives_from(builtin.string, builtin.integer));
1010        assert!(!builtin.derives_from(builtin.decimal, builtin.integer)); // Reverse
1011        assert!(!builtin.derives_from(builtin.float, builtin.double));
1012    }
1013
1014    #[test]
1015    fn test_derives_from_any_simple_type() {
1016        let mut schema_set = create_test_schema_set();
1017        let builtin = BuiltinTypes::new(&mut schema_set);
1018
1019        // All simple types derive from anySimpleType
1020        assert!(builtin.derives_from(builtin.string, builtin.any_simple_type));
1021        assert!(builtin.derives_from(builtin.integer, builtin.any_simple_type));
1022        assert!(builtin.derives_from(builtin.byte, builtin.any_simple_type));
1023        assert!(builtin.derives_from(builtin.nmtokens, builtin.any_simple_type));
1024    }
1025
1026    #[test]
1027    fn test_get_base_type() {
1028        let mut schema_set = create_test_schema_set();
1029        let builtin = BuiltinTypes::new(&mut schema_set);
1030
1031        // anySimpleType has no base
1032        assert!(builtin.get_base_type(builtin.any_simple_type).is_none());
1033
1034        // Primitives derive from anySimpleType
1035        assert_eq!(
1036            builtin.get_base_type(builtin.string),
1037            Some(builtin.any_simple_type)
1038        );
1039
1040        // normalizedString derives from string
1041        assert_eq!(
1042            builtin.get_base_type(builtin.normalized_string),
1043            Some(builtin.string)
1044        );
1045
1046        // integer derives from decimal
1047        assert_eq!(
1048            builtin.get_base_type(builtin.integer),
1049            Some(builtin.decimal)
1050        );
1051    }
1052
1053    #[test]
1054    fn test_builtin_base_type_hierarchy() {
1055        // Test the get_builtin_base_type function directly
1056        assert_eq!(get_builtin_base_type(XmlTypeCode::AnySimpleType), None);
1057        assert_eq!(
1058            get_builtin_base_type(XmlTypeCode::String),
1059            Some(XmlTypeCode::AnySimpleType)
1060        );
1061        assert_eq!(
1062            get_builtin_base_type(XmlTypeCode::NormalizedString),
1063            Some(XmlTypeCode::String)
1064        );
1065        assert_eq!(
1066            get_builtin_base_type(XmlTypeCode::Token),
1067            Some(XmlTypeCode::NormalizedString)
1068        );
1069        assert_eq!(
1070            get_builtin_base_type(XmlTypeCode::NCName),
1071            Some(XmlTypeCode::Name)
1072        );
1073        assert_eq!(
1074            get_builtin_base_type(XmlTypeCode::Integer),
1075            Some(XmlTypeCode::Decimal)
1076        );
1077        assert_eq!(
1078            get_builtin_base_type(XmlTypeCode::Long),
1079            Some(XmlTypeCode::Integer)
1080        );
1081        assert_eq!(
1082            get_builtin_base_type(XmlTypeCode::Byte),
1083            Some(XmlTypeCode::Short)
1084        );
1085    }
1086}