hydrate_schema/schema_def/
schema_def.rs

1use crate::{
2    HashMap, HashSet, Schema, SchemaDynamicArray, SchemaEnum, SchemaEnumSymbol, SchemaFingerprint,
3    SchemaMap, SchemaNamedType, SchemaRecord, SchemaRecordField, SchemaStaticArray,
4};
5use std::fmt::Formatter;
6use std::hash::{Hash, Hasher};
7use std::path::PathBuf;
8use uuid::Uuid;
9
10#[derive(Debug)]
11pub enum SchemaDefValidationError {
12    DuplicateFieldName(String, String),
13    ReferencedNamedTypeNotFound(String, String),
14    // Map keys cannot be f32/f64, containers, nullables, records, etc.
15    InvalidMapKeyType(String, String),
16    // AssetRef can only reference named types that are records
17    InvalidAssetRefInnerType(String, String),
18}
19
20impl std::fmt::Display for SchemaDefValidationError {
21    fn fmt(
22        &self,
23        f: &mut Formatter<'_>,
24    ) -> std::fmt::Result {
25        match self {
26            SchemaDefValidationError::DuplicateFieldName(schema_name, duplicate_field_name) => {
27                write!(
28                    f,
29                    "Schema {} has a duplicate field {}",
30                    schema_name, duplicate_field_name
31                )
32            }
33            SchemaDefValidationError::ReferencedNamedTypeNotFound(
34                schema_name,
35                referenced_named_type_not_found,
36            ) => write!(
37                f,
38                "Schema {} references a type {} that wasn't found",
39                schema_name, referenced_named_type_not_found
40            ),
41            SchemaDefValidationError::InvalidMapKeyType(schema_name, invalid_map_key_type) => {
42                write!(
43                    f,
44                    "Schema {} has map with key of type {}, but this type cannot be used as a key",
45                    schema_name, invalid_map_key_type
46                )
47            }
48            SchemaDefValidationError::InvalidAssetRefInnerType(
49                schema_name,
50                invalid_asset_ref_inner_type,
51            ) => write!(
52                f,
53                "Schema {} references an AssetRef that references {} but it is not a record",
54                schema_name, invalid_asset_ref_inner_type
55            ),
56        }
57    }
58}
59
60pub type SchemaDefValidationResult<T> = Result<T, SchemaDefValidationError>;
61
62#[derive(Debug)]
63pub enum SchemaDefParserError {
64    Str(&'static str),
65    String(String),
66    ValidationError(SchemaDefValidationError),
67}
68
69impl From<SchemaDefValidationError> for SchemaDefParserError {
70    fn from(validation_error: SchemaDefValidationError) -> Self {
71        SchemaDefParserError::ValidationError(validation_error)
72    }
73}
74
75pub type SchemaDefParserResult<T> = Result<T, SchemaDefParserError>;
76
77#[derive(Debug)]
78pub struct SchemaDefStaticArray {
79    pub(super) item_type: Box<SchemaDefType>,
80    pub(super) length: usize,
81}
82
83impl SchemaDefStaticArray {
84    fn apply_type_aliases(
85        &mut self,
86        aliases: &HashMap<String, String>,
87    ) {
88        self.item_type.apply_type_aliases(aliases);
89    }
90
91    fn collect_all_related_types(
92        &self,
93        types: &mut HashSet<String>,
94    ) {
95        self.item_type.collect_all_related_types(types);
96    }
97
98    fn partial_hash<T: Hasher>(
99        &self,
100        hasher: &mut T,
101    ) {
102        self.item_type.partial_hash(hasher);
103        self.length.hash(hasher);
104    }
105
106    fn to_schema(
107        &self,
108        named_types: &HashMap<String, SchemaDefNamedType>,
109        fingerprints: &HashMap<String, SchemaFingerprint>,
110    ) -> SchemaStaticArray {
111        SchemaStaticArray::new(
112            Box::new(self.item_type.to_schema(named_types, fingerprints)),
113            self.length,
114        )
115    }
116}
117
118#[derive(Debug)]
119pub struct SchemaDefDynamicArray {
120    pub(super) item_type: Box<SchemaDefType>,
121}
122
123impl SchemaDefDynamicArray {
124    pub fn new(item_type: Box<SchemaDefType>) -> Self {
125        SchemaDefDynamicArray { item_type }
126    }
127
128    fn apply_type_aliases(
129        &mut self,
130        aliases: &HashMap<String, String>,
131    ) {
132        self.item_type.apply_type_aliases(aliases);
133    }
134
135    fn collect_all_related_types(
136        &self,
137        types: &mut HashSet<String>,
138    ) {
139        self.item_type.collect_all_related_types(types);
140    }
141
142    fn partial_hash<T: Hasher>(
143        &self,
144        hasher: &mut T,
145    ) {
146        self.item_type.partial_hash(hasher);
147    }
148
149    fn to_schema(
150        &self,
151        named_types: &HashMap<String, SchemaDefNamedType>,
152        fingerprints: &HashMap<String, SchemaFingerprint>,
153    ) -> SchemaDynamicArray {
154        SchemaDynamicArray::new(Box::new(
155            self.item_type.to_schema(named_types, fingerprints),
156        ))
157    }
158}
159
160#[derive(Debug)]
161pub struct SchemaDefMap {
162    pub(super) key_type: Box<SchemaDefType>,
163    pub(super) value_type: Box<SchemaDefType>,
164}
165
166impl SchemaDefMap {
167    fn apply_type_aliases(
168        &mut self,
169        aliases: &HashMap<String, String>,
170    ) {
171        self.key_type.apply_type_aliases(aliases);
172        self.value_type.apply_type_aliases(aliases);
173    }
174
175    fn collect_all_related_types(
176        &self,
177        types: &mut HashSet<String>,
178    ) {
179        self.key_type.collect_all_related_types(types);
180        self.value_type.collect_all_related_types(types);
181    }
182
183    fn partial_hash<T: Hasher>(
184        &self,
185        hasher: &mut T,
186    ) {
187        self.key_type.partial_hash(hasher);
188        self.value_type.partial_hash(hasher);
189    }
190
191    fn to_schema(
192        &self,
193        named_types: &HashMap<String, SchemaDefNamedType>,
194        fingerprints: &HashMap<String, SchemaFingerprint>,
195    ) -> SchemaMap {
196        SchemaMap::new(
197            Box::new(self.key_type.to_schema(named_types, fingerprints)),
198            Box::new(self.value_type.to_schema(named_types, fingerprints)),
199        )
200    }
201}
202
203//prior art: https://benui.ca/unreal/uproperty/#general-points
204//display name
205//category
206//tooltip
207//min
208//max
209//clamp min
210//clamp max
211//units
212//array fixed size?
213//which field to use to describe the element (for arrays that can't be inlined). Could be like "Field {x} is {y}"
214//rgb/xyz/rgba/xyzw
215//bitmasks/bitflags?
216//deprecation
217//allowed classes for references. can we have some concept of interfaces?
218//code generation
219//if it is an asset that can be created in ui
220//if it is import data
221//hide in inspector?
222
223#[derive(Default, Debug, Clone)]
224pub struct SchemaDefRecordFieldMarkup {
225    // If set, we use this name instead of the class name in most UI
226    pub display_name: Option<String>,
227    // Additional documentation that may show in a tooltip, for example
228    pub description: Option<String>,
229
230    // Groups related fields together
231    pub category: Option<String>,
232
233    // Clamp min/max cause the UI to force numeric values to be within the given range
234    pub clamp_min: Option<f64>,
235    pub clamp_max: Option<f64>,
236
237    // ui min/max sets the begin/end point for sliding values but user can still set a value outside
238    // this range
239    pub ui_min: Option<f64>,
240    pub ui_max: Option<f64>,
241}
242
243impl SchemaDefRecordFieldMarkup {
244    pub fn clamp_min(&self) -> f64 {
245        self.clamp_min.unwrap_or(f64::MIN)
246    }
247
248    pub fn clamp_max(&self) -> f64 {
249        self.clamp_max.unwrap_or(f64::MAX)
250    }
251
252    pub fn ui_min(&self) -> f64 {
253        // The greater of clamp/ui min
254        self.clamp_min
255            .unwrap_or(f64::MIN)
256            .max(self.ui_min.unwrap_or(f64::MIN))
257    }
258
259    pub fn ui_max(&self) -> f64 {
260        // The lesser of clamp/ui max
261        self.clamp_max
262            .unwrap_or(f64::MAX)
263            .min(self.ui_max.unwrap_or(f64::MAX))
264    }
265
266    pub fn has_min_bound(&self) -> bool {
267        self.ui_min.is_some() || self.clamp_min.is_some()
268    }
269
270    pub fn has_max_bound(&self) -> bool {
271        self.ui_max.is_some() || self.clamp_max.is_some()
272    }
273}
274
275#[derive(Debug)]
276pub struct SchemaDefRecordField {
277    pub(super) field_name: String,
278    pub(super) field_uuid: Uuid,
279    pub(super) aliases: Vec<String>,
280    pub(super) field_type: SchemaDefType,
281    pub(super) markup: SchemaDefRecordFieldMarkup,
282}
283
284impl SchemaDefRecordField {
285    pub fn new(
286        field_name: String,
287        field_uuid: Uuid,
288        aliases: Vec<String>,
289        field_type: SchemaDefType,
290        markup: SchemaDefRecordFieldMarkup,
291    ) -> SchemaDefValidationResult<Self> {
292        Ok(SchemaDefRecordField {
293            field_name,
294            field_uuid,
295            aliases,
296            field_type,
297            markup,
298        })
299    }
300
301    fn apply_type_aliases(
302        &mut self,
303        aliases: &HashMap<String, String>,
304    ) {
305        self.field_type.apply_type_aliases(aliases);
306    }
307
308    fn collect_all_related_types(
309        &self,
310        types: &mut HashSet<String>,
311    ) {
312        self.field_type.collect_all_related_types(types);
313    }
314
315    fn partial_hash<T: Hasher>(
316        &self,
317        hasher: &mut T,
318    ) {
319        // Should this be field UUID instead?
320        self.field_name.hash(hasher);
321        self.field_type.partial_hash(hasher);
322    }
323
324    fn to_schema(
325        &self,
326        named_types: &HashMap<String, SchemaDefNamedType>,
327        fingerprints: &HashMap<String, SchemaFingerprint>,
328    ) -> SchemaRecordField {
329        SchemaRecordField::new(
330            self.field_name.clone(),
331            self.field_uuid,
332            self.aliases.clone().into_boxed_slice(),
333            self.field_type.to_schema(named_types, fingerprints),
334            self.markup.clone(),
335        )
336    }
337}
338
339#[derive(Default, Debug, Clone)]
340pub struct SchemaDefRecordMarkup {
341    // If set, we use this name instead of the class name in most UI
342    pub display_name: Option<String>,
343
344    pub default_thumbnail: Option<PathBuf>,
345
346    // Tags can be used to query for a list of records that meet some criteria
347    pub tags: HashSet<String>,
348    //description: String,
349}
350
351//TODO: Verify we don't have dupe field names
352#[derive(Debug)]
353pub struct SchemaDefRecord {
354    pub(super) type_name: String,
355    pub(super) type_uuid: Uuid,
356    pub(super) aliases: Vec<String>,
357    pub(super) fields: Vec<SchemaDefRecordField>,
358    pub(super) markup: SchemaDefRecordMarkup,
359}
360
361impl SchemaDefRecord {
362    pub fn new(
363        type_name: String,
364        type_uuid: Uuid,
365        aliases: Vec<String>,
366        fields: Vec<SchemaDefRecordField>,
367        markup: SchemaDefRecordMarkup,
368    ) -> SchemaDefValidationResult<Self> {
369        // Check names are unique
370        for i in 0..fields.len() {
371            for j in 0..i {
372                if fields[i].field_name == fields[j].field_name {
373                    Err(SchemaDefValidationError::DuplicateFieldName(
374                        type_name.clone(),
375                        fields[i].field_name.to_string(),
376                    ))?;
377                }
378            }
379        }
380
381        Ok(SchemaDefRecord {
382            type_name,
383            type_uuid,
384            aliases,
385            fields,
386            markup,
387        })
388    }
389
390    pub(crate) fn fields(&self) -> &Vec<SchemaDefRecordField> {
391        &self.fields
392    }
393
394    fn apply_type_aliases(
395        &mut self,
396        aliases: &HashMap<String, String>,
397    ) {
398        for field in &mut self.fields {
399            field.apply_type_aliases(aliases);
400        }
401    }
402
403    fn collect_all_related_types(
404        &self,
405        types: &mut HashSet<String>,
406    ) {
407        types.insert(self.type_name.clone());
408        for field in &self.fields {
409            field.collect_all_related_types(types);
410        }
411    }
412
413    fn partial_hash<T: Hasher>(
414        &self,
415        hasher: &mut T,
416    ) {
417        // should this be type_uuid instead?
418        self.type_name.hash(hasher);
419
420        // should this sort by field_uuid instead?
421        let mut sorted_fields: Vec<_> = self.fields.iter().collect();
422        sorted_fields.sort_by_key(|x| &x.field_name);
423
424        for field in sorted_fields {
425            //println!("field {}", field.field_name);
426            field.partial_hash(hasher);
427        }
428    }
429
430    fn to_schema(
431        &self,
432        named_types: &HashMap<String, SchemaDefNamedType>,
433        fingerprints: &HashMap<String, SchemaFingerprint>,
434    ) -> SchemaRecord {
435        let fingerprint = *fingerprints.get(&self.type_name).unwrap();
436
437        let mut fields = Vec::with_capacity(self.fields.len());
438        for field in &self.fields {
439            fields.push(field.to_schema(named_types, fingerprints));
440        }
441
442        SchemaRecord::new(
443            self.type_name.clone(),
444            self.type_uuid,
445            fingerprint,
446            self.aliases.clone().into_boxed_slice(),
447            fields,
448            self.markup.clone(),
449        )
450    }
451}
452
453#[derive(Debug)]
454pub struct SchemaDefEnumSymbol {
455    pub(super) symbol_name: String,
456    pub(super) symbol_uuid: Uuid,
457    pub(super) aliases: Vec<String>,
458}
459
460impl SchemaDefEnumSymbol {
461    pub fn new(
462        symbol_name: String,
463        symbol_uuid: Uuid,
464        aliases: Vec<String>,
465    ) -> SchemaDefValidationResult<Self> {
466        Ok(SchemaDefEnumSymbol {
467            symbol_name,
468            symbol_uuid,
469            aliases,
470        })
471    }
472
473    fn partial_hash<T: Hasher>(
474        &self,
475        hasher: &mut T,
476    ) {
477        // should this use symbol_uuid instead?
478        self.symbol_name.hash(hasher);
479    }
480
481    fn to_schema(&self) -> SchemaEnumSymbol {
482        SchemaEnumSymbol::new(
483            self.symbol_name.clone(),
484            self.symbol_uuid,
485            self.aliases.clone().into_boxed_slice(),
486        )
487    }
488}
489
490//TODO: Verify that we don't have dupe symbol names or values
491#[derive(Debug)]
492pub struct SchemaDefEnum {
493    pub(super) type_name: String,
494    pub(super) type_uuid: Uuid,
495    pub(super) aliases: Vec<String>,
496    pub(super) symbols: Vec<SchemaDefEnumSymbol>,
497}
498
499impl SchemaDefEnum {
500    pub fn new(
501        type_name: String,
502        type_uuid: Uuid,
503        aliases: Vec<String>,
504        symbols: Vec<SchemaDefEnumSymbol>,
505    ) -> SchemaDefValidationResult<Self> {
506        Ok(SchemaDefEnum {
507            type_name,
508            type_uuid,
509            aliases,
510            symbols,
511        })
512    }
513
514    fn apply_type_aliases(
515        &mut self,
516        _aliases: &HashMap<String, String>,
517    ) {
518    }
519
520    fn collect_all_related_types(
521        &self,
522        types: &mut HashSet<String>,
523    ) {
524        types.insert(self.type_name.clone());
525    }
526
527    fn partial_hash<T: Hasher>(
528        &self,
529        hasher: &mut T,
530    ) {
531        // should this use type_uuid instead?
532        self.type_name.hash(hasher);
533
534        // should this sort by symbol_uuid instead?
535        let mut sorted_symbols: Vec<_> = self.symbols.iter().collect();
536        sorted_symbols.sort_by(|a, b| a.symbol_name.cmp(&b.symbol_name));
537
538        for symbol in sorted_symbols {
539            symbol.partial_hash(hasher);
540        }
541    }
542
543    fn to_schema(
544        &self,
545        named_types: &HashMap<String, SchemaFingerprint>,
546    ) -> SchemaEnum {
547        let fingerprint = *named_types.get(&self.type_name).unwrap();
548
549        let mut symbols = Vec::with_capacity(self.symbols.len());
550        for symbol in &self.symbols {
551            symbols.push(symbol.to_schema());
552        }
553
554        SchemaEnum::new(
555            self.type_name.clone(),
556            self.type_uuid,
557            fingerprint,
558            self.aliases.clone().into_boxed_slice(),
559            symbols.into_boxed_slice(),
560        )
561    }
562}
563
564#[derive(Debug)]
565pub enum SchemaDefType {
566    Nullable(Box<SchemaDefType>),
567    Boolean,
568    I32,
569    I64,
570    U32,
571    U64,
572    F32,
573    F64,
574    Bytes,
575    String,
576    StaticArray(SchemaDefStaticArray),
577    DynamicArray(SchemaDefDynamicArray),
578    Map(SchemaDefMap),
579    AssetRef(String),  // name of the type
580    NamedType(String), // name of the type
581}
582
583impl SchemaDefType {
584    fn apply_type_aliases(
585        &mut self,
586        aliases: &HashMap<String, String>,
587    ) {
588        match self {
589            SchemaDefType::Nullable(x) => x.apply_type_aliases(aliases),
590            SchemaDefType::Boolean => {}
591            SchemaDefType::I32 => {}
592            SchemaDefType::I64 => {}
593            SchemaDefType::U32 => {}
594            SchemaDefType::U64 => {}
595            SchemaDefType::F32 => {}
596            SchemaDefType::F64 => {}
597            SchemaDefType::Bytes => {}
598            SchemaDefType::String => {}
599            SchemaDefType::StaticArray(x) => x.apply_type_aliases(aliases),
600            SchemaDefType::DynamicArray(x) => x.apply_type_aliases(aliases),
601            SchemaDefType::Map(x) => x.apply_type_aliases(aliases),
602            SchemaDefType::AssetRef(x) => {
603                let alias = aliases.get(x);
604                if let Some(alias) = alias {
605                    *x = alias.clone();
606                }
607            }
608            SchemaDefType::NamedType(x) => {
609                let alias = aliases.get(x);
610                if let Some(alias) = alias {
611                    *x = alias.clone();
612                }
613            }
614        }
615    }
616
617    fn collect_all_related_types(
618        &self,
619        types: &mut HashSet<String>,
620    ) {
621        match self {
622            SchemaDefType::Nullable(x) => x.collect_all_related_types(types),
623            SchemaDefType::Boolean => {}
624            SchemaDefType::I32 => {}
625            SchemaDefType::I64 => {}
626            SchemaDefType::U32 => {}
627            SchemaDefType::U64 => {}
628            SchemaDefType::F32 => {}
629            SchemaDefType::F64 => {}
630            SchemaDefType::Bytes => {}
631            SchemaDefType::String => {}
632            SchemaDefType::StaticArray(x) => x.collect_all_related_types(types),
633            SchemaDefType::DynamicArray(x) => x.collect_all_related_types(types),
634            SchemaDefType::Map(x) => x.collect_all_related_types(types),
635            SchemaDefType::AssetRef(x) => {
636                types.insert(x.clone());
637            }
638            SchemaDefType::NamedType(x) => {
639                types.insert(x.clone());
640            }
641        }
642    }
643
644    fn partial_hash<T: Hasher>(
645        &self,
646        hasher: &mut T,
647    ) {
648        //println!("ty {:?}", self);
649        match self {
650            SchemaDefType::Nullable(x) => {
651                "Nullable".hash(hasher);
652                x.partial_hash(hasher);
653            }
654            SchemaDefType::Boolean => "Boolean".hash(hasher),
655            SchemaDefType::I32 => "I32".hash(hasher),
656            SchemaDefType::I64 => "I64".hash(hasher),
657            SchemaDefType::U32 => "U32".hash(hasher),
658            SchemaDefType::U64 => "U64".hash(hasher),
659            SchemaDefType::F32 => "F32".hash(hasher),
660            SchemaDefType::F64 => "F64".hash(hasher),
661            SchemaDefType::Bytes => "Bytes".hash(hasher),
662            SchemaDefType::String => "String".hash(hasher),
663            SchemaDefType::StaticArray(x) => {
664                "StaticArray".hash(hasher);
665                x.partial_hash(hasher);
666            }
667            SchemaDefType::DynamicArray(x) => {
668                "DynamicArray".hash(hasher);
669                x.partial_hash(hasher);
670            }
671            SchemaDefType::Map(x) => {
672                "Map".hash(hasher);
673                x.partial_hash(hasher);
674            }
675            SchemaDefType::AssetRef(x) => {
676                "AssetRef".hash(hasher);
677                x.hash(hasher);
678            }
679            SchemaDefType::NamedType(x) => {
680                "NamedType".hash(hasher);
681                x.hash(hasher);
682            }
683        }
684    }
685
686    fn to_schema(
687        &self,
688        named_types: &HashMap<String, SchemaDefNamedType>,
689        fingerprints: &HashMap<String, SchemaFingerprint>,
690    ) -> Schema {
691        match self {
692            SchemaDefType::Nullable(x) => {
693                Schema::Nullable(Box::new(x.to_schema(named_types, fingerprints)))
694            }
695            SchemaDefType::Boolean => Schema::Boolean,
696            SchemaDefType::I32 => Schema::I32,
697            SchemaDefType::I64 => Schema::I64,
698            SchemaDefType::U32 => Schema::U32,
699            SchemaDefType::U64 => Schema::U64,
700            SchemaDefType::F32 => Schema::F32,
701            SchemaDefType::F64 => Schema::F64,
702            SchemaDefType::Bytes => Schema::Bytes,
703            SchemaDefType::String => Schema::String,
704            SchemaDefType::StaticArray(x) => {
705                Schema::StaticArray(x.to_schema(named_types, fingerprints))
706            }
707            SchemaDefType::DynamicArray(x) => {
708                Schema::DynamicArray(x.to_schema(named_types, fingerprints))
709            }
710            SchemaDefType::Map(x) => Schema::Map(x.to_schema(named_types, fingerprints)),
711            SchemaDefType::AssetRef(x) => Schema::AssetRef(*fingerprints.get(x).unwrap()),
712            SchemaDefType::NamedType(x) => {
713                let named_type = named_types.get(x).unwrap();
714                match named_type {
715                    SchemaDefNamedType::Record(_) => Schema::Record(*fingerprints.get(x).unwrap()),
716                    SchemaDefNamedType::Enum(_) => Schema::Enum(*fingerprints.get(x).unwrap()),
717                }
718            }
719        }
720    }
721}
722
723pub enum SchemaDefNamedType {
724    Record(SchemaDefRecord),
725    Enum(SchemaDefEnum),
726}
727
728impl SchemaDefNamedType {
729    pub(super) fn type_name(&self) -> &str {
730        match self {
731            SchemaDefNamedType::Record(x) => &x.type_name,
732            SchemaDefNamedType::Enum(x) => &x.type_name,
733        }
734    }
735
736    pub(super) fn type_uuid(&self) -> Uuid {
737        match self {
738            SchemaDefNamedType::Record(x) => x.type_uuid,
739            SchemaDefNamedType::Enum(x) => x.type_uuid,
740        }
741    }
742
743    pub(super) fn aliases(&self) -> &[String] {
744        match self {
745            SchemaDefNamedType::Record(x) => &x.aliases,
746            SchemaDefNamedType::Enum(x) => &x.aliases,
747        }
748    }
749
750    pub(super) fn apply_type_aliases(
751        &mut self,
752        aliases: &HashMap<String, String>,
753    ) {
754        match self {
755            SchemaDefNamedType::Record(x) => x.apply_type_aliases(aliases),
756            SchemaDefNamedType::Enum(x) => x.apply_type_aliases(aliases),
757        }
758    }
759
760    pub(super) fn collect_all_related_types(
761        &self,
762        types: &mut HashSet<String>,
763    ) {
764        match self {
765            SchemaDefNamedType::Record(x) => x.collect_all_related_types(types),
766            SchemaDefNamedType::Enum(x) => x.collect_all_related_types(types),
767        }
768    }
769
770    pub(super) fn partial_hash<T: Hasher>(
771        &self,
772        hasher: &mut T,
773    ) {
774        match self {
775            SchemaDefNamedType::Record(x) => {
776                //println!("record");
777                "record".hash(hasher);
778                x.partial_hash(hasher);
779            }
780            SchemaDefNamedType::Enum(x) => {
781                "enum".hash(hasher);
782                x.partial_hash(hasher);
783            }
784        }
785    }
786
787    pub(super) fn to_schema(
788        &self,
789        named_types: &HashMap<String, SchemaDefNamedType>,
790        fingerprints: &HashMap<String, SchemaFingerprint>,
791    ) -> SchemaNamedType {
792        match self {
793            SchemaDefNamedType::Record(x) => {
794                SchemaNamedType::Record(x.to_schema(named_types, fingerprints))
795            }
796            SchemaDefNamedType::Enum(x) => SchemaNamedType::Enum(x.to_schema(fingerprints)),
797        }
798    }
799}