1use crate::authority::DocumentAuthority;
23use crate::ion_schema_element::IonSchemaElementType;
24use crate::isl::isl_import::{IslImport, IslImportType};
25use crate::isl::isl_type::IslType;
26use crate::isl::{IslSchema, IslVersion};
27use crate::result::{
28 invalid_schema_error, invalid_schema_error_raw, unresolvable_schema_error,
29 unresolvable_schema_error_raw, IonSchemaError, IonSchemaResult,
30};
31use crate::schema::Schema;
32use crate::types::{BuiltInTypeDefinition, Nullability, TypeDefinitionImpl, TypeDefinitionKind};
33use crate::{is_isl_version_marker, is_reserved_word, UserReservedFields};
34use ion_rs::IonType;
35use ion_rs::{Annotations, Element};
36use std::collections::{HashMap, HashSet};
37use std::io::ErrorKind;
38use std::sync::Arc;
39
40#[derive(Debug, Clone, Default)]
76pub struct PendingTypes {
77 builtin_type_ids_by_name: HashMap<String, TypeId>,
78 ids_by_name: HashMap<String, TypeId>,
79 parent: Option<(String, TypeId)>,
80 types_by_id: Vec<Option<TypeDefinitionKind>>, }
82
83impl PendingTypes {
84 pub fn update_type_store(
100 &mut self,
101 type_store: &mut TypeStore,
102 load_isl_import: Option<&IslImport>,
103 isl_type_names: &HashSet<&str>,
104 ) -> IonSchemaResult<bool> {
105 if let Some(import) = load_isl_import {
107 match import {
108 IslImport::Schema(_) => {
109 self.update_type_store_with_all_isl_imported_types(
110 None,
111 type_store,
112 isl_type_names,
113 )?;
114 }
115 IslImport::Type(isl_import) => {
116 if let Some(named_type_def) =
118 self.get_type_by_name_for_import(isl_import.type_name(), type_store)
119 {
120 type_store
121 .add_isl_imported_type(isl_import.alias().as_ref(), named_type_def?);
122 self.update_type_store_with_all_isl_imported_types(
123 Some(isl_import.type_name()),
124 type_store,
125 isl_type_names,
126 )?;
127 } else {
128 return Ok(false);
132 }
133 }
134 IslImport::TypeAlias(isl_import) => {
135 if type_store
137 .imported_type_ids_by_name
138 .contains_key(isl_import.alias().as_ref().unwrap())
139 {
140 return Ok(true);
142 } else if let Some(named_type_def) =
143 self.get_type_by_name_for_import(isl_import.type_name(), type_store)
144 {
145 let aliased_type_def = named_type_def?
146 .with_name(isl_import.alias().as_ref().unwrap().to_owned());
147 type_store
148 .add_isl_imported_type(isl_import.alias().as_ref(), aliased_type_def);
149 self.update_type_store_with_all_isl_imported_types(
150 Some(isl_import.type_name()),
151 type_store,
152 isl_type_names,
153 )?;
154 } else {
155 return Ok(false);
159 }
160 }
161 }
162 } else {
163 self.update_type_store_with_all_types(type_store, isl_type_names)?;
165 }
166 self.types_by_id.clear();
167 self.ids_by_name.clear();
168 Ok(true)
169 }
170
171 fn get_type_by_name_for_import(
174 &self,
175 import_type_name: &str,
176 type_store: &mut TypeStore,
177 ) -> Option<IonSchemaResult<TypeDefinitionImpl>> {
178 match self.ids_by_name.get(import_type_name) {
179 Some(id) => self.types_by_id[*id]
180 .to_owned()
181 .map(|type_def| match type_def {
182 TypeDefinitionKind::Named(named_type_def) => Ok(named_type_def),
183 TypeDefinitionKind::Anonymous(_) => {
184 unreachable!(
185 "The TypeDefinition for the imported type '{}' was Anonymous.",
186 import_type_name
187 )
188 }
189 TypeDefinitionKind::BuiltIn(_) => {
190 unreachable!(
191 "The TypeDefinition for the imported type '{}' was a builtin type.",
192 import_type_name
193 )
194 }
195 }),
196 None => {
197 match type_store.get_defined_type_id_or_imported_type_id_by_name(import_type_name) {
198 Some(id) => match type_store.types_by_id[*id].to_owned() {
199 TypeDefinitionKind::Named(named_type_def) => Some(Ok(named_type_def)),
200 TypeDefinitionKind::Anonymous(_) => {
201 unreachable!(
202 "The TypeDefinition for the imported type '{}' was Anonymous.",
203 import_type_name
204 )
205 }
206 TypeDefinitionKind::BuiltIn(_) => {
207 unreachable!(
208 "The TypeDefinition for the imported type '{}' was a builtin type.",
209 import_type_name
210 )
211 }
212 },
213 None => None,
214 }
215 }
216 }
217 }
218
219 fn update_type_store_with_all_types(
221 &self,
222 type_store: &mut TypeStore,
223 isl_type_names: &HashSet<&str>,
224 ) -> IonSchemaResult<()> {
225 for optional_type in &self.types_by_id {
226 let type_def = optional_type.to_owned().ok_or_else(|| {
228 unresolvable_schema_error_raw("Unable to load schema due to unresolvable type")
229 })?;
230
231 match type_def {
232 TypeDefinitionKind::Named(named_type_def) => {
233 if named_type_def.is_deferred_type_def()
236 && !isl_type_names
237 .contains(named_type_def.name().as_ref().unwrap().as_str())
238 {
239 return unresolvable_schema_error(format!(
240 "Unable to load schema due to unresolvable type {}",
241 named_type_def.name().as_ref().unwrap()
242 ));
243 }
244 type_store.add_named_type(named_type_def)
245 }
246 TypeDefinitionKind::Anonymous(anonymous_type_def) => {
247 type_store.add_anonymous_type(anonymous_type_def)
248 }
249 TypeDefinitionKind::BuiltIn(builtin_type) => {
250 type_store.add_builtin_type(&builtin_type)
251 }
252 };
253 }
254 Ok(())
255 }
256
257 fn update_type_store_with_all_isl_imported_types(
263 &self,
264 isl_imported_type_name: Option<&str>,
265 type_store: &mut TypeStore,
266 isl_type_names: &HashSet<&str>,
267 ) -> IonSchemaResult<()> {
268 for optional_type in &self.types_by_id {
269 let type_def = optional_type.to_owned().ok_or_else(|| {
271 unresolvable_schema_error_raw("Unable to load schema due to unresolvable type")
272 })?;
273
274 match type_def.to_owned() {
275 TypeDefinitionKind::Named(named_type_def) => {
276 match isl_imported_type_name {
277 None => {
278 if named_type_def.is_deferred_type_def()
281 && !isl_type_names
282 .contains(named_type_def.name().as_ref().unwrap().as_str())
283 {
284 return unresolvable_schema_error(format!(
285 "Unable to load schema due to unresolvable type {}",
286 named_type_def.name().as_ref().unwrap()
287 ));
288 }
289 type_store.add_isl_imported_type(None, named_type_def);
291 }
292 Some(import_type_name) => {
293 if named_type_def.is_deferred_type_def()
296 && !isl_type_names
297 .contains(named_type_def.name().as_ref().unwrap().as_str())
298 {
299 return unresolvable_schema_error(format!(
300 "Unable to load schema due to unresolvable type {}",
301 named_type_def.name().as_ref().unwrap()
302 ));
303 }
304 if named_type_def.name().as_ref().unwrap().eq(import_type_name) {
306 continue;
307 }
308 type_store
310 .types_by_id
311 .push(TypeDefinitionKind::Named(named_type_def));
312 }
313 }
314 }
315 TypeDefinitionKind::Anonymous(anonymous_type_def) => {
316 type_store.add_anonymous_type(anonymous_type_def);
317 }
318 TypeDefinitionKind::BuiltIn(builtin_type) => {
319 type_store.add_builtin_type(&builtin_type);
320 }
321 };
322 }
323 Ok(())
324 }
325
326 pub(crate) fn get_total_types(&self, type_store: &mut TypeStore) -> usize {
328 self.types_by_id.len() + type_store.types_by_id.len()
329 }
330
331 pub(crate) fn get_type_id_by_name(
334 &self,
335 name: &str,
336 type_store: &mut TypeStore,
337 ) -> Option<TypeId> {
338 match self.ids_by_name.get(name) {
339 Some(id) => Some(*id + type_store.types_by_id.len()),
340 None => type_store
341 .get_defined_type_id_or_imported_type_id_by_name(name)
342 .copied(),
343 }
344 }
345
346 pub(crate) fn update_named_type(
349 &mut self,
350 type_id: TypeId,
351 name: &str,
352 type_def: TypeDefinitionImpl,
353 type_store: &mut TypeStore,
354 ) -> TypeId {
355 if let Some(exists) = self.ids_by_name.get(name) {
356 return exists.to_owned() + type_store.types_by_id.len();
357 }
358
359 if let Some(exists) = type_store.imported_type_ids_by_name.get(name) {
360 return exists.to_owned();
361 }
362
363 match type_store.update_deferred_type_def(type_def.to_owned(), name) {
364 None => {
365 let type_id = type_id - type_store.types_by_id.len();
366 self.ids_by_name.insert(name.to_owned(), type_id);
367 self.types_by_id[type_id] = Some(TypeDefinitionKind::Named(type_def));
368 type_id + type_store.types_by_id.len()
369 }
370 Some(exists) => exists,
371 }
372 }
373
374 pub(crate) fn update_anonymous_type(
377 &mut self,
378 type_id: TypeId,
379 type_def: TypeDefinitionImpl,
380 type_store: &mut TypeStore,
381 ) -> TypeId {
382 self.types_by_id[type_id - type_store.types_by_id.len()] =
383 Some(TypeDefinitionKind::Anonymous(type_def));
384 type_id
385 }
386
387 pub(crate) fn add_parent(&mut self, name: String, type_store: &mut TypeStore) {
389 self.parent = Some((name, self.types_by_id.len() + type_store.types_by_id.len()))
394 }
395
396 pub(crate) fn get_parent(&self) -> &Option<(String, TypeId)> {
398 &self.parent
399 }
400
401 pub(crate) fn clear_parent(&mut self) {
403 self.parent = None
404 }
405
406 pub(crate) fn add_type(
408 &mut self,
409 type_store: &mut TypeStore,
410 type_name: Option<String>,
411 ) -> TypeId {
412 if let Some(name) = type_name {
413 if let Some(exists) = self.ids_by_name.get(&name) {
414 return exists.to_owned() + type_store.types_by_id.len();
415 }
416 if let Some(exists) = type_store.get_defined_type_id_or_imported_type_id_by_name(&name)
417 {
418 return exists.to_owned();
419 }
420 }
421 let type_id = self.types_by_id.len();
422 self.types_by_id.push(None);
423 type_id + type_store.types_by_id.len()
424 }
425
426 pub(crate) fn add_deferred_type_with_name(
428 &mut self,
429 alias: &str,
430 type_store: &mut TypeStore,
431 ) -> TypeId {
432 let type_id = self.types_by_id.len();
433 self.ids_by_name.insert(alias.to_owned(), type_id);
434 self.types_by_id.push(Some(TypeDefinitionKind::Named(
435 TypeDefinitionImpl::new_deferred_type_def(alias.to_owned()),
436 )));
437 type_id + type_store.types_by_id.len()
438 }
439}
440
441static DERIVED_ISL_TYPES: [&str; 9] = [
444 "type::{ name: lob, one_of: [ blob, clob ] }",
445 "type::{ name: number, one_of: [ decimal, float, int ] }",
446 "type::{ name: text, one_of: [ string, symbol ] }",
447 "type::{ name: $lob, one_of: [ $blob, $clob ] }",
448 "type::{ name: $number, one_of: [ $decimal, $float, $int ] }",
449 "type::{ name: $text, one_of: [ $string, $symbol ] }",
450 "type::{ name: $any, one_of: [ $blob, $bool, $clob, $decimal,
451 $float, $int, $string, $symbol, $timestamp,
452 $list, $sexp, $struct, $null, document ] }",
453 "type::{ name: nothing, not: $any }",
454 "type::{ name: any, one_of: [ blob, bool, clob, decimal,
455 float, int, string, symbol, timestamp,
456 list, sexp, struct, document ] }",
457];
458
459pub type TypeId = usize;
460
461#[derive(Debug, Clone)]
463pub struct TypeStore {
464 builtin_type_ids_by_name: HashMap<String, TypeId>, imported_type_ids_by_name: HashMap<String, TypeId>, ids_by_name: HashMap<String, TypeId>, types_by_id: Vec<TypeDefinitionKind>,
468}
469
470impl Default for TypeStore {
471 fn default() -> Self {
472 let mut type_store = Self {
473 builtin_type_ids_by_name: HashMap::new(),
474 imported_type_ids_by_name: HashMap::new(),
475 ids_by_name: HashMap::new(),
476 types_by_id: Vec::new(),
477 };
478 type_store
479 .preload()
480 .expect("The type store didn't preload with built-in types correctly");
481 type_store
482 }
483}
484
485impl TypeStore {
486 pub(crate) fn preload(&mut self) -> IonSchemaResult<()> {
490 let isl_version = IslVersion::V1_0;
491 use IonSchemaElementType::*;
494 let built_in_atomic_types: [IonSchemaElementType; 12] = [
495 Int, Float, Decimal, Timestamp, String, Symbol, Bool, Blob, Clob, SExp, List, Struct,
496 ];
497 for atomic_type in built_in_atomic_types {
499 self.add_builtin_type(&BuiltInTypeDefinition::Atomic(
500 atomic_type.to_owned(),
501 Nullability::NotNullable,
502 ));
503 }
504
505 for atomic_type in built_in_atomic_types {
507 self.add_builtin_type(&BuiltInTypeDefinition::Atomic(
508 atomic_type.to_owned(),
509 Nullability::Nullable,
510 ));
511 }
512
513 self.add_builtin_type(&BuiltInTypeDefinition::Atomic(Null, Nullability::Nullable));
515
516 self.add_builtin_type(&BuiltInTypeDefinition::Atomic(
518 Document,
519 Nullability::NotNullable,
520 ));
521
522 let pending_types = &mut PendingTypes::default();
524 for text in DERIVED_ISL_TYPES {
525 let isl_type = IslType::from_owned_element(
526 isl_version,
527 &Element::read_one(text.as_bytes()).expect("parsing failed unexpectedly"),
528 &mut vec![],
529 )
530 .unwrap();
531 let type_def = BuiltInTypeDefinition::parse_from_isl_type(
532 isl_version,
533 &isl_type,
534 self,
535 pending_types,
536 )?;
537 self.add_builtin_type(&type_def);
538 }
539 Ok(())
540 }
541
542 pub(crate) fn get_types(&self) -> Vec<TypeId> {
544 self.ids_by_name.values().cloned().collect()
545 }
546
547 pub(crate) fn get_imports(&self) -> Vec<TypeId> {
549 self.imported_type_ids_by_name.values().cloned().collect()
550 }
551
552 pub(crate) fn get_imported_type_id_by_name(&self, name: &str) -> Option<&TypeId> {
555 self.imported_type_ids_by_name.get(name)
556 }
557
558 pub(crate) fn get_type_by_name(&self, name: &str) -> Option<&TypeDefinitionKind> {
561 self.ids_by_name
562 .get(name)
563 .and_then(|id| self.types_by_id.get(*id))
564 .or_else(|| {
565 self.imported_type_ids_by_name
566 .get(name)
567 .and_then(|id| self.types_by_id.get(*id))
568 })
569 }
570
571 pub(crate) fn get_built_in_type_id_or_defined_type_id_by_name(
574 &self,
575 name: &str,
576 ) -> Option<&TypeId> {
577 self.ids_by_name
578 .get(name)
579 .or_else(|| self.builtin_type_ids_by_name.get(name))
580 }
581
582 pub(crate) fn get_defined_type_id_or_imported_type_id_by_name(
585 &self,
586 name: &str,
587 ) -> Option<&TypeId> {
588 self.ids_by_name
589 .get(name)
590 .or_else(|| self.imported_type_ids_by_name.get(name))
591 }
592
593 pub(crate) fn get_type_id_by_name(&self, name: &str) -> Option<&TypeId> {
596 self.ids_by_name
597 .get(name)
598 .or_else(|| self.imported_type_ids_by_name.get(name))
599 .or_else(|| self.builtin_type_ids_by_name.get(name))
600 }
601
602 pub(crate) fn get_type_def_by_name(&self, name: &str) -> Option<&TypeDefinitionKind> {
605 self.ids_by_name
606 .get(name)
607 .and_then(|id| self.types_by_id.get(*id))
608 }
609
610 pub(crate) fn get_builtin_type_id(&self, type_name: &str) -> Option<TypeId> {
613 self.builtin_type_ids_by_name
614 .get(type_name)
615 .map(|t| t.to_owned())
616 }
617
618 pub(crate) fn get_type_by_id(&self, id: TypeId) -> Option<&TypeDefinitionKind> {
621 self.types_by_id.get(id)
622 }
623
624 pub(crate) fn add_named_type(&mut self, type_def: TypeDefinitionImpl) -> TypeId {
627 let name = type_def.name().as_ref().unwrap();
628 if let Some(exists) = self.ids_by_name.get(name) {
629 return exists.to_owned();
630 }
631 let type_id = self.types_by_id.len();
632 self.ids_by_name.insert(name.to_owned(), type_id);
633 self.types_by_id.push(TypeDefinitionKind::Named(type_def));
634 type_id
635 }
636
637 pub(crate) fn update_deferred_type_def(
641 &mut self,
642 type_def: TypeDefinitionImpl,
643 name: &str,
644 ) -> Option<TypeId> {
645 if let Some(exists) = self.ids_by_name.get(name) {
646 if let Some(TypeDefinitionKind::Named(existing_type_def)) = self.get_type_by_id(*exists)
647 {
648 if existing_type_def.is_deferred_type_def() {
651 self.types_by_id[*exists] = TypeDefinitionKind::Named(type_def);
652 }
653 }
654 return Some(*exists);
655 }
656 None
657 }
658
659 pub(crate) fn add_builtin_type(
662 &mut self,
663 builtin_type_definition: &BuiltInTypeDefinition,
664 ) -> TypeId {
665 let builtin_type_name = match builtin_type_definition {
666 BuiltInTypeDefinition::Atomic(ion_type, is_nullable) => match is_nullable {
667 Nullability::Nullable => format!("${ion_type}"),
668 Nullability::NotNullable => format!("{ion_type}"),
669 },
670 BuiltInTypeDefinition::Derived(other_type) => other_type.name().to_owned().unwrap(),
671 };
672
673 if let Some(exists) = self.builtin_type_ids_by_name.get(&builtin_type_name) {
674 return exists.to_owned();
675 }
676 let type_id = self.types_by_id.len();
677 self.builtin_type_ids_by_name
678 .insert(builtin_type_name, type_id);
679 self.types_by_id.push(TypeDefinitionKind::BuiltIn(
680 builtin_type_definition.to_owned(),
681 ));
682 type_id
683 }
684
685 pub(crate) fn add_isl_imported_type(
688 &mut self,
689 alias: Option<&String>,
690 type_def: TypeDefinitionImpl,
691 ) -> TypeId {
692 let name = match alias {
693 None => type_def.name().as_ref().unwrap(),
694 Some(name) => name,
695 };
696
697 if let Some(exists) = self.imported_type_ids_by_name.get(name) {
698 return exists.to_owned();
699 }
700 let type_id = self.types_by_id.len();
701 self.imported_type_ids_by_name
702 .insert(name.to_owned(), type_id);
703 self.types_by_id.push(TypeDefinitionKind::Named(type_def));
704 type_id
705 }
706
707 pub(crate) fn add_anonymous_type(&mut self, type_def: TypeDefinitionImpl) -> TypeId {
709 let type_id = self.types_by_id.len();
710 self.types_by_id
711 .push(TypeDefinitionKind::Anonymous(type_def));
712 type_id
713 }
714}
715
716pub struct Resolver {
718 authorities: Vec<Box<dyn DocumentAuthority>>,
719 resolved_schema_cache: HashMap<String, Arc<Schema>>,
720}
721
722impl Resolver {
723 pub fn new(authorities: Vec<Box<dyn DocumentAuthority>>) -> Self {
724 Self {
725 authorities,
726 resolved_schema_cache: HashMap::new(),
727 }
728 }
729
730 pub fn schema_from_isl_types<A: AsRef<str>, B: Into<Vec<IslType>>>(
731 &self,
732 isl_version: IslVersion,
733 id: A,
734 isl_types: B,
735 ) -> IonSchemaResult<Schema> {
736 let isl_types = isl_types.into();
737 let mut type_store = TypeStore::default();
739 let pending_types = &mut PendingTypes::default();
740
741 let isl_type_names: HashSet<&str> =
744 HashSet::from_iter(isl_types.iter().filter_map(|t| t.name()));
745
746 for isl_type in &isl_types {
747 match &isl_type.name() {
749 Some(isl_type_name) => {
750 let has_other_isl_constraints = isl_type
752 .constraints()
753 .iter()
754 .any(|c| c.version != isl_version);
755
756 if has_other_isl_constraints {
757 return invalid_schema_error(format!("ISL type: {isl_type_name} contains constraints from another ISL version. Only use {isl_version} constraints for this method."));
758 }
759
760 TypeDefinitionImpl::parse_from_isl_type_and_update_pending_types(
761 isl_version,
762 isl_type,
763 &mut type_store,
764 pending_types,
765 )?
766 }
767 None => {
768 return invalid_schema_error("Top level types must be named type definitions");
770 }
771 };
772 }
773
774 pending_types.update_type_store(&mut type_store, None, &isl_type_names)?;
776 Ok(Schema::new(id, Arc::new(type_store)))
777 }
778
779 pub fn isl_schema_from_elements<I: Iterator<Item = Element>>(
781 &mut self,
782 elements: I,
783 id: &str,
784 ) -> IonSchemaResult<IslSchema> {
785 let mut isl_imports: Vec<IslImport> = vec![];
787 let mut isl_types: Vec<IslType> = vec![];
788 let mut isl_inline_imports: Vec<IslImportType> = vec![];
789 let mut open_content = vec![];
790 let mut isl_user_reserved_fields = UserReservedFields::default();
791 let mut isl_version = IslVersion::V1_0;
792
793 let mut found_header = false;
794 let mut found_footer = false;
795 let mut found_type_definition = false;
796 let mut found_isl_version_marker = false;
797
798 for value in elements {
799 let annotations: &Annotations = value.annotations();
800
801 if !found_isl_version_marker
803 && value.ion_type() == IonType::Symbol
804 && is_isl_version_marker(value.as_text().unwrap())
805 {
806 isl_version = match value.as_text().unwrap() {
808 "$ion_schema_1_0" => IslVersion::V1_0,
809 "$ion_schema_2_0" => IslVersion::V2_0,
810 _ => {
811 return invalid_schema_error(format!(
812 "Unsupported Ion Schema Language version: {value}"
813 ));
814 }
815 };
816 found_isl_version_marker = true;
817 } else if annotations.contains("schema_header") {
818 if isl_version == IslVersion::V2_0 {
819 if found_type_definition {
820 return invalid_schema_error(
821 "The schema header must come before top level type definitions",
822 );
823 }
824
825 if found_header {
826 return invalid_schema_error(
827 "Schema must only contain a single schema header",
828 );
829 }
830
831 if annotations.len() > 1 {
832 return invalid_schema_error(
833 "schema header must not have any other annotations then `schema_header`",
834 );
835 }
836 }
837
838 found_header = true;
839
840 if !found_isl_version_marker {
843 found_isl_version_marker = true;
844 }
845
846 let schema_header = try_to!(value.as_struct());
847 if let Some(imports) = schema_header.get("imports").and_then(|it| it.as_sequence())
848 {
849 for import in imports.elements() {
850 let isl_import = IslImport::from_ion_element(import)?;
851 isl_imports.push(isl_import);
852 }
853 }
854 if isl_version == IslVersion::V2_0 {
855 if let Some(user_reserved_fields_element) =
856 schema_header.get("user_reserved_fields")
857 {
858 if !user_reserved_fields_element.annotations().is_empty() {
859 return invalid_schema_error(
860 "User reserved field must be an unannotated struct",
861 )?;
862 }
863 let user_reserved_fields_struct = user_reserved_fields_element
864 .as_struct()
865 .ok_or(invalid_schema_error_raw(
866 "User reserved field must be a non-null struct",
867 ))?;
868
869 isl_user_reserved_fields =
870 UserReservedFields::from_ion_elements(user_reserved_fields_struct)?;
871 }
872 isl_user_reserved_fields.validate_field_names_in_header(schema_header)?;
873 }
874 }
875 else if annotations.contains("type") {
877 found_type_definition = true;
878
879 if isl_version == IslVersion::V2_0 && annotations.len() > 1 {
880 return invalid_schema_error(
881 "Top level types definitions must not have any other annotations then `type`",
882 );
883 }
884 if !found_isl_version_marker {
887 found_isl_version_marker = true;
888 }
889
890 let isl_type: IslType =
892 IslType::from_owned_element(isl_version, &value, &mut isl_inline_imports)?;
893 if isl_type.name().is_none() {
894 return invalid_schema_error(
896 "Top level types must contain field `name` in their definition",
897 );
898 }
899
900 if isl_version == IslVersion::V2_0 {
901 isl_user_reserved_fields.validate_field_names_in_type(&isl_type)?;
902 }
903
904 if value.as_struct().unwrap().get("occurs").is_some() {
906 return invalid_schema_error(
907 "Top level types must not contain `occurs` field in their definition",
908 );
909 }
910
911 isl_types.push(isl_type);
912 }
913 else if annotations.contains("schema_footer") {
915 found_footer = true;
916 if isl_version == IslVersion::V2_0 {
917 if annotations.len() > 1 {
918 return invalid_schema_error(
919 "schema footer must not have any other annotations then `schema_footer`",
920 );
921 }
922 let schema_footer = try_to!(value.as_struct());
923 isl_user_reserved_fields.validate_field_names_in_footer(schema_footer)?;
924 }
925 } else {
926 if value.ion_type() == IonType::Symbol
928 && !value.is_null()
929 && is_isl_version_marker(value.as_text().unwrap())
930 {
931 return invalid_schema_error(
932 "top level open content can not be an Ion Schema version marker",
933 );
934 }
935
936 if isl_version == IslVersion::V2_0
937 && value
938 .annotations()
939 .iter()
940 .any(|a| is_reserved_word(a.text().unwrap()))
941 {
942 return invalid_schema_error(
943 "top level open content may not be annotated with any reserved keyword",
944 );
945 }
946
947 open_content.push(value);
948 continue;
949 }
950 }
951
952 if found_footer ^ found_header {
953 return invalid_schema_error("For any schema while a header and footer are both optional, a footer is required if a header is present (and vice-versa).");
954 }
955
956 match isl_version {
957 IslVersion::V1_0 => Ok(IslSchema::schema_v_1_0(
958 id,
959 isl_imports,
960 isl_types,
961 isl_inline_imports,
962 open_content,
963 )),
964 IslVersion::V2_0 => Ok(IslSchema::schema_v_2_0(
965 id,
966 isl_user_reserved_fields,
967 isl_imports,
968 isl_types,
969 isl_inline_imports,
970 open_content,
971 )),
972 }
973 }
974
975 pub fn schema_from_isl_schema(
977 &mut self,
978 isl_version: IslVersion,
979 isl: IslSchema,
980 type_store: &mut TypeStore,
981 load_isl_import: Option<&IslImport>,
982 ) -> IonSchemaResult<Arc<Schema>> {
983 let mut added_imported_type_to_type_store = false;
987
988 if isl_version != isl.version() {
989 return invalid_schema_error(format!(
990 "Expected {isl_version} schema but found {}",
991 isl.version()
992 ));
993 }
994
995 let isl_types = isl.types();
996
997 for isl_inline_imported_type in isl.inline_imported_types() {
1000 let import_id = isl_inline_imported_type.id();
1001 let inline_imported_type = self.load_schema(
1002 import_id,
1003 type_store,
1004 Some(&IslImport::Type(isl_inline_imported_type.to_owned())),
1005 )?;
1006 }
1007
1008 for isl_import in isl.imports() {
1010 let import_id = isl_import.id();
1011 let imported_schema = self.load_schema(import_id, type_store, Some(isl_import))?;
1012 }
1013
1014 let isl_type_names: HashSet<&str> =
1017 HashSet::from_iter(isl.types().filter_map(|t| t.name()));
1018
1019 for isl_type in isl_types {
1021 let pending_types = &mut PendingTypes::default();
1022
1023 if let Some(isl_type_name) = &isl_type.name() {
1024 let has_other_isl_constraints = isl_type
1026 .constraints()
1027 .iter()
1028 .any(|c| c.version != isl_version);
1029
1030 if has_other_isl_constraints {
1031 return invalid_schema_error(format!("ISL type: {isl_type_name} contains constraints from other ISL version. Only use {isl_version} constraints for this method."));
1032 }
1033
1034 let type_id: TypeId =
1036 TypeDefinitionImpl::parse_from_isl_type_and_update_pending_types(
1037 isl_version,
1038 isl_type,
1039 type_store,
1040 pending_types,
1041 )?;
1042 }
1043
1044 added_imported_type_to_type_store =
1046 pending_types.update_type_store(type_store, load_isl_import, &isl_type_names)?;
1047 }
1048
1049 if load_isl_import.is_some() && !added_imported_type_to_type_store {
1052 unreachable!(
1053 "Unable to load import: {} as the type/types were not added to the type_store correctly",
1054 isl.id()
1055 );
1056 }
1057
1058 let schema = Arc::new(Schema::new(isl.id(), Arc::new(type_store.clone())));
1059
1060 match load_isl_import {
1064 None => {
1065 self.resolved_schema_cache
1066 .insert(isl.id(), Arc::clone(&schema));
1067 }
1068 Some(IslImport::Schema(_)) => {
1069 self.resolved_schema_cache
1070 .insert(isl.id(), Arc::clone(&schema));
1071 }
1072 _ => {
1073 }
1075 }
1076
1077 Ok(schema)
1078 }
1079
1080 fn load_schema<A: AsRef<str>>(
1087 &mut self,
1088 id: A,
1089 type_store: &mut TypeStore,
1090 load_isl_import: Option<&IslImport>,
1091 ) -> IonSchemaResult<Arc<Schema>> {
1092 let id: &str = id.as_ref();
1093
1094 if let Some(schema) = self.resolved_schema_cache.get(id) {
1095 return Ok(Arc::clone(schema));
1096 }
1097
1098 for authority in &self.authorities {
1099 return match authority.elements(id) {
1100 Err(error) => match error {
1101 IonSchemaError::IoError { source } => match source.kind() {
1102 ErrorKind::NotFound => continue,
1103 _ => Err(IonSchemaError::IoError { source }),
1104 },
1105 _ => Err(error),
1106 },
1107 Ok(schema_content) => {
1108 let isl = self.isl_schema_from_elements(schema_content.into_iter(), id)?;
1109 self.schema_from_isl_schema(isl.version(), isl, type_store, load_isl_import)
1110 }
1111 };
1112 }
1113 unresolvable_schema_error("Unable to load schema: ".to_owned() + id)
1114 }
1115
1116 fn load_isl_schema<A: AsRef<str>>(
1123 &mut self,
1124 id: A,
1125 load_isl_import: Option<&IslImport>,
1126 ) -> IonSchemaResult<IslSchema> {
1127 let id: &str = id.as_ref();
1128
1129 for authority in &self.authorities {
1130 return match authority.elements(id) {
1131 Ok(schema_content) => self.isl_schema_from_elements(schema_content.into_iter(), id),
1132 Err(IonSchemaError::IoError { source: e }) if e.kind() == ErrorKind::NotFound => {
1133 continue;
1134 }
1135 Err(error) => Err(error),
1136 };
1137 }
1138 unresolvable_schema_error("Unable to load ISL model: ".to_owned() + id)
1139 }
1140}
1141
1142pub struct SchemaSystem {
1149 resolver: Resolver,
1150}
1151
1152impl SchemaSystem {
1154 pub fn new(authorities: Vec<Box<dyn DocumentAuthority>>) -> Self {
1155 Self {
1156 resolver: Resolver::new(authorities),
1157 }
1158 }
1159
1160 pub fn load_schema<A: AsRef<str>>(&mut self, id: A) -> IonSchemaResult<Arc<Schema>> {
1167 self.resolver
1168 .load_schema(id, &mut TypeStore::default(), None)
1169 }
1170
1171 pub fn new_schema(&mut self, schema_content: &[u8], id: &str) -> IonSchemaResult<Arc<Schema>> {
1173 let elements = Element::read_all(schema_content)?;
1174 let isl = self
1175 .resolver
1176 .isl_schema_from_elements(elements.into_iter(), id)?;
1177 self.resolver
1178 .schema_from_isl_schema(isl.version(), isl, &mut TypeStore::default(), None)
1179 }
1180
1181 pub fn load_isl_schema<A: AsRef<str>>(&mut self, id: A) -> IonSchemaResult<IslSchema> {
1185 self.resolver.load_isl_schema(id, None)
1186 }
1187
1188 pub fn new_isl_schema(
1190 &mut self,
1191 schema_content: &[u8],
1192 id: &str,
1193 ) -> IonSchemaResult<IslSchema> {
1194 let elements = Element::read_all(schema_content)?;
1195 self.resolver
1196 .isl_schema_from_elements(elements.into_iter(), id)
1197 }
1198
1199 pub fn load_schema_from_isl_schema_v1_0(
1205 &mut self,
1206 isl: IslSchema,
1207 ) -> IonSchemaResult<Arc<Schema>> {
1208 self.resolver
1209 .schema_from_isl_schema(IslVersion::V1_0, isl, &mut TypeStore::default(), None)
1210 }
1211
1212 pub fn load_schema_from_isl_schema_v2_0(
1218 &mut self,
1219 isl: IslSchema,
1220 ) -> IonSchemaResult<Arc<Schema>> {
1221 self.resolver
1222 .schema_from_isl_schema(IslVersion::V2_0, isl, &mut TypeStore::default(), None)
1223 }
1224
1225 fn authorities(&mut self) -> &[Box<dyn DocumentAuthority>] {
1227 &self.resolver.authorities
1228 }
1229
1230 fn add_authority(&mut self, authority: Box<dyn DocumentAuthority>) {
1232 self.resolver.authorities.push(authority);
1233 }
1234
1235 fn with_authority(&mut self, authority: Box<dyn DocumentAuthority>) {
1237 let authorities: Vec<Box<dyn DocumentAuthority>> = vec![authority];
1238 self.resolver.authorities = authorities;
1239 }
1240
1241 fn with_authorities(&mut self, authorities: Vec<Box<dyn DocumentAuthority>>) {
1244 self.resolver.authorities = authorities;
1245 }
1246
1247 pub fn schema_from_isl_types_v1_0<A: AsRef<str>, B: Into<Vec<IslType>>>(
1250 &self,
1251 id: A,
1252 isl_types: B,
1253 ) -> IonSchemaResult<Schema> {
1254 self.resolver
1255 .schema_from_isl_types(IslVersion::V1_0, id, isl_types)
1256 }
1257
1258 pub fn schema_from_isl_types_v2_0<A: AsRef<str>, B: Into<Vec<IslType>>>(
1261 &self,
1262 id: A,
1263 isl_types: B,
1264 ) -> IonSchemaResult<Schema> {
1265 self.resolver
1266 .schema_from_isl_types(IslVersion::V2_0, id, isl_types)
1267 }
1268}
1269
1270#[cfg(test)]
1271mod schema_system_tests {
1272 use super::*;
1273 use crate::authority::{FileSystemDocumentAuthority, MapDocumentAuthority};
1274 use crate::isl::isl_constraint;
1275 use crate::isl::isl_type;
1276 use crate::isl::isl_type_reference;
1277 use crate::system::IonSchemaError::InvalidSchemaError;
1278 use std::path::Path;
1279
1280 #[test]
1281 fn schema_system_add_authorities_test() {
1282 let mut schema_system = SchemaSystem::new(vec![Box::new(
1283 FileSystemDocumentAuthority::new(Path::new("")),
1284 )]);
1285 schema_system.add_authority(Box::new(FileSystemDocumentAuthority::new(Path::new(
1286 "test",
1287 ))));
1288 let schema_system_authorities = schema_system.authorities();
1289 assert_eq!(2, schema_system_authorities.len());
1290 }
1291
1292 #[test]
1293 fn schema_system_with_authority_test() {
1294 let mut schema_system = SchemaSystem::new(vec![Box::new(
1295 FileSystemDocumentAuthority::new(Path::new("")),
1296 )]);
1297 schema_system.with_authority(Box::new(FileSystemDocumentAuthority::new(Path::new(
1298 "test",
1299 ))));
1300 let schema_system_authorities = schema_system.authorities();
1301 assert_eq!(1, schema_system_authorities.len());
1302 }
1303
1304 #[test]
1305 fn schema_system_with_authorities_test() {
1306 let mut schema_system = SchemaSystem::new(vec![Box::new(
1307 FileSystemDocumentAuthority::new(Path::new("")),
1308 )]);
1309 schema_system.with_authorities(vec![
1310 Box::new(FileSystemDocumentAuthority::new(Path::new("test"))),
1311 Box::new(FileSystemDocumentAuthority::new(Path::new("ion"))),
1312 ]);
1313 let schema_system_authorities = schema_system.authorities();
1314 assert_eq!(2, schema_system_authorities.len());
1315 }
1316
1317 #[test]
1318 fn schema_system_map_authority_with_type_alias_import_test() {
1319 let map_authority = [
1321 (
1322 "sample_number.isl",
1323 r#"
1324 schema_header::{
1325 imports: [{ id: "sample_decimal.isl", type: my_decimal, as: other_decimal }],
1326 }
1327
1328 type::{
1329 name: my_int,
1330 type: int,
1331 }
1332
1333 type::{
1334 name: my_number,
1335 all_of: [
1336 my_int,
1337 other_decimal,
1338 ],
1339 }
1340
1341 schema_footer::{
1342 }
1343 "#,
1344 ),
1345 (
1346 "sample_decimal.isl",
1347 r#"
1348 schema_header::{
1349 imports: [],
1350 }
1351
1352 type::{
1353 name: my_decimal,
1354 type: decimal,
1355 }
1356
1357 type::{
1358 name: my_string,
1359 type: string,
1360 }
1361
1362 schema_footer::{
1363 }
1364 "#,
1365 ),
1366 ];
1367 let mut schema_system =
1368 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1369 let schema = schema_system.load_schema("sample_number.isl");
1371 assert!(schema.is_ok());
1372 }
1373
1374 #[test]
1375 fn schema_system_map_authority_with_type_import_test() {
1376 let map_authority = [
1378 (
1379 "sample_number.isl",
1380 r#"
1381 schema_header::{
1382 imports: [{ id: "sample_decimal.isl", type: my_decimal }],
1383 }
1384
1385 type::{
1386 name: my_int,
1387 type: int,
1388 }
1389
1390 type::{
1391 name: my_number,
1392 all_of: [
1393 my_int,
1394 my_decimal,
1395 ],
1396 }
1397
1398 schema_footer::{
1399 }
1400 "#,
1401 ),
1402 (
1403 "sample_decimal.isl",
1404 r#"
1405 schema_header::{
1406 imports: [],
1407 }
1408
1409 type::{
1410 name: my_decimal,
1411 type: decimal,
1412 }
1413
1414 type::{
1415 name: my_string,
1416 type: string,
1417 }
1418
1419 schema_footer::{
1420 }
1421 "#,
1422 ),
1423 ];
1424 let mut schema_system =
1425 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1426 let schema = schema_system.load_schema("sample_number.isl");
1428 assert!(schema.is_ok());
1429
1430 let isl_imported_type = schema.as_ref().unwrap().get_imported_type("my_decimal");
1432 assert!(isl_imported_type.is_some());
1433 let isl_defined_type = schema
1434 .as_ref()
1435 .unwrap()
1436 .get_built_in_or_defined_type("my_number");
1437 assert!(isl_defined_type.is_some());
1438 let isl_type = schema.as_ref().unwrap().get_type("my_decimal");
1439 assert!(isl_type.is_some());
1440 }
1441
1442 #[test]
1443 fn schema_system_map_authority_with_schema_import_test() {
1444 let map_authority = [
1446 (
1447 "sample_import_string.isl",
1448 r#"
1449 schema_header::{
1450 imports: [{ id: "sample_string.isl" }],
1451 }
1452
1453 type::{
1454 name: import_string,
1455 type: my_string,
1456 }
1457
1458 schema_footer::{
1459 }
1460 "#,
1461 ),
1462 (
1463 "sample_string.isl",
1464 r#"
1465 schema_header::{
1466 imports: [],
1467 }
1468
1469 type::{
1470 name: my_string,
1471 type: string,
1472 }
1473
1474 schema_footer::{
1475 }
1476 "#,
1477 ),
1478 ];
1479 let mut schema_system =
1480 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1481 let schema = schema_system.load_schema("sample_import_string.isl");
1483 assert!(schema.is_ok());
1484 }
1485
1486 #[test]
1487 fn schema_system_map_authority_with_inline_import_type_test() {
1488 let map_authority = [
1490 (
1491 "sample_number.isl",
1492 r#"
1493 schema_header::{
1494 imports: [],
1495 }
1496
1497 type::{
1498 name: my_int,
1499 type: int,
1500 }
1501
1502 type::{
1503 name: my_number,
1504 all_of: [
1505 my_int,
1506 { id: "sample_decimal.isl", type: my_decimal },
1507 ],
1508 }
1509
1510 schema_footer::{
1511 }
1512 "#,
1513 ),
1514 (
1515 "sample_decimal.isl",
1516 r#"
1517 schema_header::{
1518 imports: [],
1519 }
1520
1521 type::{
1522 name: my_decimal,
1523 type: decimal,
1524 }
1525
1526 type::{
1527 name: my_string,
1528 type: string,
1529 }
1530
1531 schema_footer::{
1532 }
1533 "#,
1534 ),
1535 ];
1536 let mut schema_system =
1537 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1538 let schema = schema_system.load_schema("sample_number.isl");
1540 assert!(schema.is_ok());
1541 }
1542
1543 #[test]
1544 fn schema_system_map_authority_with_incorrect_inline_import_type_test() {
1545 let map_authority = [
1547 (
1548 "sample_number.isl",
1549 r#"
1550 $ion_schema_2_0
1551 schema_header::{
1552 imports: [],
1553 }
1554
1555 type::{
1556 name: my_int,
1557 type: int,
1558 }
1559
1560 type::{
1561 name: my_number,
1562 all_of: [
1563 my_int,
1564 { id: "sample_decimal.isl", type: my_decimal, as: other_decimal},
1565 ],
1566 }
1567
1568 schema_footer::{
1569 }
1570 "#,
1571 ),
1572 (
1573 "sample_decimal.isl",
1574 r#"
1575 $ion_schema_2_0
1576 schema_header::{
1577 imports: [],
1578 }
1579
1580 type::{
1581 name: my_decimal,
1582 type: decimal,
1583 }
1584
1585 type::{
1586 name: my_string,
1587 type: string,
1588 }
1589
1590 schema_footer::{
1591 }
1592 "#,
1593 ),
1594 ];
1595 let mut schema_system =
1596 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1597 let schema = schema_system.load_schema("sample_number.isl");
1599 assert!(schema.is_err());
1600 assert!(matches!(schema.unwrap_err(), InvalidSchemaError { .. }));
1601 }
1602
1603 #[test]
1604 fn schema_system_map_authority_with_isl_builtin_derived_types() {
1605 let map_authority = [
1607 (
1608 "sample.isl",
1609 r#"
1610 schema_header::{
1611 imports: [ { id: "sample_builtin_types.isl" } ],
1612 }
1613
1614 type::{
1615 name: my_number,
1616 type: number,
1617 }
1618
1619 type::{
1620 name: my_type,
1621 one_of: [
1622 my_number,
1623 my_text,
1624 my_lob
1625 ],
1626 }
1627
1628 schema_footer::{
1629 }
1630 "#,
1631 ),
1632 (
1633 "sample_builtin_types.isl",
1634 r#"
1635 schema_header::{
1636 imports: [],
1637 }
1638
1639 type::{
1640 name: my_text,
1641 type: text,
1642 }
1643
1644 type::{
1645 name: my_lob,
1646 type: lob,
1647 }
1648
1649 schema_footer::{
1650 }
1651 "#,
1652 ),
1653 ];
1654 let mut schema_system =
1655 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1656 let schema = schema_system.load_schema("sample.isl");
1658 assert!(schema.is_ok());
1659 }
1660
1661 #[test]
1662 fn schema_system_map_authority_with_isl_builtin_derived_nullable_types() {
1663 let map_authority = [
1665 (
1666 "sample.isl",
1667 r#"
1668 schema_header::{
1669 imports: [ { id: "sample_builtin_nullable_types.isl" } ],
1670 }
1671
1672 type::{
1673 name: my_number,
1674 type: $number,
1675 }
1676
1677 type::{
1678 name: my_any,
1679 type: $any,
1680 }
1681
1682 type::{
1683 name: my_type,
1684 one_of: [
1685 my_number,
1686 my_text,
1687 my_lob
1688 ],
1689 }
1690
1691 schema_footer::{
1692 }
1693 "#,
1694 ),
1695 (
1696 "sample_builtin_nullable_types.isl",
1697 r#"
1698 schema_header::{
1699 imports: [],
1700 }
1701
1702 type::{
1703 name: my_text,
1704 type: $text,
1705 }
1706
1707 type::{
1708 name: my_lob,
1709 type: $lob,
1710 }
1711
1712 schema_footer::{
1713 }
1714 "#,
1715 ),
1716 ];
1717 let mut schema_system =
1718 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1719 let schema = schema_system.load_schema("sample.isl");
1721 assert!(schema.is_ok());
1722 }
1723
1724 #[test]
1725 fn schema_system_map_authority_with_valid_transitive_type_import_test() {
1726 let map_authority = [
1728 (
1729 "sample.isl",
1730 r#"
1731 schema_header::{
1732 imports: [ { id: "sample_builtin_nullable_types.isl", type: my_text } ],
1733 }
1734
1735 type::{
1736 name: my_type,
1737 type: my_text
1738 }
1739
1740 schema_footer::{
1741 }
1742 "#,
1743 ),
1744 (
1745 "sample_builtin_nullable_types.isl",
1746 r#"
1747 schema_header::{
1748 imports: [],
1749 }
1750
1751 type::{
1752 name: my_text,
1753 one_of: [
1754 my_string,
1755 symbol,
1756 ],
1757 }
1758
1759 type::{
1760 name: my_string,
1761 type: string,
1762 }
1763
1764 schema_footer::{
1765 }
1766 "#,
1767 ),
1768 ];
1769 let mut schema_system =
1770 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1771 let schema = schema_system.load_schema("sample.isl");
1773 assert!(schema.is_ok());
1774 }
1775
1776 #[test]
1777 fn schema_system_map_authority_with_invalid_transitive_type_import_test() {
1778 let map_authority = [
1780 (
1781 "sample.isl",
1782 r#"
1783 schema_header::{
1784 imports: [ { id: "sample_builtin_nullable_types.isl", type: my_text } ],
1785 }
1786
1787 type::{
1788 name: my_type,
1789 type: my_string, // this type reference was not imported by name in sample.isl
1790 }
1791
1792 schema_footer::{
1793 }
1794 "#,
1795 ),
1796 (
1797 "sample_builtin_nullable_types.isl",
1798 r#"
1799 schema_header::{
1800 imports: [],
1801 }
1802
1803 type::{
1804 name: my_text,
1805 one_of: [
1806 my_string,
1807 symbol,
1808 ],
1809 }
1810
1811 type::{
1812 name: my_string,
1813 type: string,
1814 }
1815
1816 schema_footer::{
1817 }
1818 "#,
1819 ),
1820 ];
1821 let mut schema_system =
1822 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1823 let schema = schema_system.load_schema("sample.isl");
1825 assert!(schema.is_err());
1826 }
1827
1828 #[test]
1829 fn schema_system_map_authority_with_multiple_type_definitions() {
1830 let map_authority = [(
1832 "sample.isl",
1833 r#"
1834 schema_header::{
1835 imports: [],
1836 }
1837
1838 type::{
1839 name: my_text,
1840 one_of: [
1841 my_string,
1842 symbol,
1843 ],
1844 }
1845
1846 type::{
1847 name: my_string,
1848 type: string,
1849 }
1850
1851 schema_footer::{
1852 }
1853 "#,
1854 )];
1855 let mut schema_system =
1856 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1857 let schema = schema_system.load_schema("sample.isl");
1859 assert!(schema.is_ok());
1860 }
1861
1862 #[test]
1863 fn schema_system_map_authority_with_multiple_codependent_type_definitions() {
1864 let map_authority = [(
1866 "sample.isl",
1867 r#"
1868 type::{
1869 name: node_a,
1870 type: list,
1871 element: node_b,
1872 }
1873
1874 type::{
1875 name: node_b,
1876 type: sexp,
1877 element: node_a,
1878 }
1879 "#,
1880 )];
1881 let mut schema_system =
1882 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1883 let schema = schema_system.load_schema("sample.isl");
1885 assert!(schema.is_ok());
1886 }
1887
1888 #[test]
1889 fn schema_system_map_authority_with_self_referencing_type_definition() {
1890 let map_authority = [(
1892 "sample.isl",
1893 r#"
1894 type::{
1895 name: binary_heap_node,
1896 type: sexp,
1897 element: { one_of: [ binary_heap_node, int ] },
1898 container_length: range::[0, 2],
1899 }
1900 "#,
1901 )];
1902 let mut schema_system =
1903 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1904 let schema = schema_system.load_schema("sample.isl");
1906 assert!(schema.is_ok());
1907 }
1908
1909 #[test]
1910 fn top_level_type_def_without_name_field() {
1911 let map_authority = [(
1913 "sample.isl",
1914 r#"
1915 type::{
1916 // top level type definition must contain a `name` field
1917 }
1918 "#,
1919 )];
1920 let mut schema_system =
1921 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1922 let schema = schema_system.load_schema("sample.isl");
1924 assert!(schema.is_err());
1925 }
1926
1927 #[test]
1928 fn top_level_type_def_with_multiple_name_field() {
1929 let map_authority = [(
1931 "sample.isl",
1932 r#"
1933 type::{
1934 name: my_type,
1935 name: new_type
1936 }
1937 "#,
1938 )];
1939 let mut schema_system =
1940 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1941 let schema = schema_system.load_schema("sample.isl");
1943 assert!(schema.is_err());
1944 }
1945
1946 #[test]
1947 fn top_level_type_def_with_non_symbol_name_field() {
1948 let map_authority = [(
1950 "sample.isl",
1951 r#"
1952 type::{
1953 name: "my_type"
1954 }
1955 "#,
1956 )];
1957 let mut schema_system =
1958 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1959 let schema = schema_system.load_schema("sample.isl");
1961 assert!(schema.is_err());
1962 }
1963
1964 #[test]
1965 fn valid_isl_version_marker_test() {
1966 let map_authority = [(
1968 "sample.isl",
1969 r#"
1970 $ion_schema_1_0
1971 "#,
1972 )];
1973 let mut schema_system =
1974 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1975 let schema = schema_system.load_schema("sample.isl");
1977 assert!(schema.is_ok());
1978 }
1979
1980 #[test]
1981 fn invalid_isl_version_marker_test() {
1982 let map_authority = [(
1984 "sample.isl",
1985 r#"
1986 $ion_schema_4_5
1987 "#,
1988 )];
1989 let mut schema_system =
1990 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
1991 let schema = schema_system.load_schema("sample.isl");
1993 assert!(schema.is_err());
1994 }
1995
1996 #[test]
1997 fn unsupported_isl_version_marker_test() {
1998 let map_authority = [(
2000 "sample.isl",
2001 r#"
2002 $ion_schema_2_1
2003 "#,
2004 )];
2005 let mut schema_system =
2006 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
2007 let schema = schema_system.load_schema("sample.isl");
2009 assert!(schema.is_err());
2010 }
2011
2012 #[test]
2013 fn open_content_test() -> IonSchemaResult<()> {
2014 let map_authority = [(
2016 "sample.isl",
2017 r#"
2018 schema_header::{}
2019
2020 type::{
2021 name: my_type,
2022 type: string,
2023 }
2024
2025 open_content_1::{
2026 unknown_constraint: "this is an open content struct"
2027 }
2028
2029 open_content_2::{
2030 unknown_constraint: "this is an open content struct"
2031 }
2032
2033 schema_footer::{}
2034 "#,
2035 )];
2036 let mut schema_system =
2037 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
2038 let schema = schema_system.load_isl_schema("sample.isl")?;
2039 let expected_open_content: Vec<_> = Element::read_all(
2040 r#"
2041 open_content_1::{
2042 unknown_constraint: "this is an open content struct"
2043 }
2044
2045 open_content_2::{
2046 unknown_constraint: "this is an open content struct"
2047 }
2048 "#
2049 .as_bytes(),
2050 )?
2051 .into_iter()
2052 .collect();
2053
2054 let open_content: Vec<_> = schema.open_content().map(|x| x.to_owned()).collect();
2056 assert_eq!(open_content.len(), 2);
2057 assert_eq!(open_content, expected_open_content);
2058 Ok(())
2059 }
2060
2061 #[test]
2062 fn unexpected_fields_in_isl_v2_0_header() {
2063 let map_authority = [(
2065 "sample.isl",
2066 r#"
2067 $ion_schema_2_0
2068 schema_header::{
2069 user_reserved_fields: {
2070 schema_header: [ foo, bar ],
2071 type: [ baz ]
2072 },
2073 baz: "this is an unexpected field in schema header"
2074 }
2075
2076 type::{
2077 name: my_type,
2078 type: string,
2079 }
2080
2081 schema_footer::{}
2082 "#,
2083 )];
2084 let mut schema_system =
2085 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
2086 let schema = schema_system.load_isl_schema("sample.isl");
2087 assert!(schema.is_err());
2088 }
2089
2090 #[test]
2091 fn unexpected_fields_in_isl_v2_0_footer() {
2092 let map_authority = [(
2094 "sample.isl",
2095 r#"
2096 $ion_schema_2_0
2097 schema_header::{
2098 user_reserved_fields: {
2099 schema_footer: [ foo, bar ],
2100 sdhema_header: [ baz ]
2101 },
2102 }
2103
2104 type::{
2105 name: my_type,
2106 type: string,
2107 }
2108
2109 schema_footer::{
2110 baz: "this is an unexpected field in schema header"
2111 }
2112 "#,
2113 )];
2114 let mut schema_system =
2115 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
2116 let schema = schema_system.load_isl_schema("sample.isl");
2117 assert!(schema.is_err());
2118 }
2119
2120 #[test]
2121 fn unexpected_fields_in_isl_v2_0_type() {
2122 let map_authority = [(
2124 "sample.isl",
2125 r#"
2126 $ion_schema_2_0
2127 schema_header::{
2128 user_reserved_fields: {
2129 schema_header: [ baz ],
2130 type: [ foo, bar ]
2131 },
2132 }
2133
2134 type::{
2135 name: my_type,
2136 type: string,
2137 baz: "this is an unexpected field in schema header"
2138 }
2139
2140 schema_footer::{}
2141 "#,
2142 )];
2143 let mut schema_system =
2144 SchemaSystem::new(vec![Box::new(MapDocumentAuthority::new(map_authority))]);
2145 let schema = schema_system.load_isl_schema("sample.isl");
2146 assert!(schema.is_err());
2147 }
2148
2149 #[test]
2150 fn load_schema_from_isl_schema_v1_0_test() {
2151 let isl_type = isl_type::v_1_0::named_type(
2153 "my_type",
2154 [isl_constraint::v_1_0::element(
2155 isl_type_reference::v_1_0::named_type_ref("int"),
2156 )],
2157 );
2158 let isl = IslSchema::schema_v_1_0("sample.isl", vec![], vec![isl_type], vec![], vec![]);
2159 let mut schema_system = SchemaSystem::new(vec![]);
2160 let schema = schema_system.load_schema_from_isl_schema_v1_0(isl);
2161
2162 assert!(schema.is_ok());
2164 }
2165
2166 #[test]
2167 fn load_schema_from_isl_schema_v2_0_test() {
2168 let isl_type = isl_type::v_2_0::named_type(
2170 "my_type",
2171 [isl_constraint::v_2_0::type_constraint(
2172 isl_type_reference::v_2_0::named_type_ref("int"),
2173 )],
2174 );
2175 let isl = IslSchema::schema_v_2_0(
2176 "sample.isl",
2177 UserReservedFields::default(),
2178 vec![],
2179 vec![isl_type],
2180 vec![],
2181 vec![],
2182 );
2183 let mut schema_system = SchemaSystem::new(vec![]);
2184 let schema = schema_system.load_schema_from_isl_schema_v2_0(isl);
2185
2186 assert!(schema.is_ok());
2188 }
2189
2190 #[test]
2191 fn load_schema_from_isl_schema_v1_0_with_isl_v2_0_constraints_test() {
2192 let isl_type = isl_type::v_1_0::named_type(
2194 "my_type",
2195 [isl_constraint::v_2_0::type_constraint(
2196 isl_type_reference::v_2_0::named_type_ref("int"),
2197 )],
2198 );
2199 let isl = IslSchema::schema_v_1_0("sample.isl", vec![], vec![isl_type], vec![], vec![]);
2200 let mut schema_system = SchemaSystem::new(vec![]);
2201 let schema = schema_system.load_schema_from_isl_schema_v1_0(isl);
2202
2203 assert!(schema.is_err());
2205 }
2206
2207 #[test]
2208 fn load_schema_from_isl_schema_v2_0_with_isl_v1_0_constraints_test() {
2209 let isl_type = isl_type::v_2_0::named_type(
2211 "my_type",
2212 [isl_constraint::v_1_0::type_constraint(
2213 isl_type_reference::v_1_0::named_type_ref("int"),
2214 )],
2215 );
2216 let isl = IslSchema::schema_v_2_0(
2217 "sample.isl",
2218 UserReservedFields::default(),
2219 vec![],
2220 vec![isl_type],
2221 vec![],
2222 vec![],
2223 );
2224 let mut schema_system = SchemaSystem::new(vec![]);
2225 let schema = schema_system.load_schema_from_isl_schema_v2_0(isl);
2226
2227 assert!(&schema.is_err());
2229 }
2230
2231 #[test]
2232 fn new_schema_test() {
2233 let mut schema_system = SchemaSystem::new(vec![]);
2234 let schema = schema_system.new_schema(
2235 br#"
2236 $ion_schema_2_0
2237 schema_header::{}
2238
2239 type::{
2240 name: my_type,
2241 type: string,
2242 }
2243
2244 schema_footer::{}
2245 "#,
2246 "sample.isl",
2247 );
2248 assert!(schema.is_ok());
2249 }
2250
2251 #[test]
2252 fn new_schema_invalid_test() {
2253 let mut schema_system = SchemaSystem::new(vec![]);
2254 let schema = schema_system.new_schema(
2255 br#"
2256 $ion_schema_2_0
2257 schema_header::{}
2258
2259 type::{
2260 name: my_type,
2261 type: nullable::string, // `nullable` annotation is not supported in ISL 2.0
2262 }
2263
2264 schema_footer::{}
2265 "#,
2266 "sample.isl",
2267 );
2268 assert!(schema.is_err());
2269 }
2270
2271 #[test]
2272 fn new_isl_schema_test() {
2273 let mut schema_system = SchemaSystem::new(vec![]);
2274 let isl = schema_system.new_isl_schema(
2275 br#"
2276 $ion_schema_2_0
2277 schema_header::{}
2278
2279 type::{
2280 name: my_type,
2281 type: string,
2282 }
2283
2284 schema_footer::{}
2285 "#,
2286 "sample.isl",
2287 );
2288 assert!(isl.is_ok());
2289 }
2290
2291 #[test]
2292 fn new_isl_schema_invalid_test() {
2293 let mut schema_system = SchemaSystem::new(vec![]);
2294 let isl = schema_system.new_isl_schema(
2295 br#"
2296 $ion_schema_2_0
2297 schema_header::{}
2298
2299 type::{
2300 name: my_type,
2301 type: nullable::string, // `nullable` annotation is not supported in ISL 2.0
2302 }
2303
2304 schema_footer::{}
2305 "#,
2306 "sample.isl",
2307 );
2308 assert!(isl.is_err());
2309 }
2310
2311 #[test]
2312 fn test_send_schema() {
2313 fn assert_send<T: Send>() {}
2314 assert_send::<Schema>();
2315 }
2316
2317 #[test]
2318 fn test_sync_schema() {
2319 fn assert_sync<T: Sync>() {}
2320 assert_sync::<Schema>();
2321 }
2322
2323 #[test]
2324 fn test_send_schema_system() {
2325 fn assert_send<T: Send>() {}
2326 assert_send::<SchemaSystem>();
2327 }
2328
2329 #[test]
2330 fn test_sync_schema_system() {
2331 fn assert_sync<T: Sync>() {}
2332 assert_sync::<SchemaSystem>();
2333 }
2334}