ion_schema/isl/
isl_type.rs1use crate::isl::isl_constraint::{IslConstraint, IslConstraintValue};
2use crate::isl::isl_import::IslImportType;
3use crate::isl::IslVersion;
4use crate::result::{invalid_schema_error, invalid_schema_error_raw, IonSchemaResult};
5use ion_rs::{Element, IonResult, StructWriter, ValueWriter, WriteAsIon};
6
7pub mod v_1_0 {
9 use crate::isl::isl_constraint::{IslConstraint, IslConstraintValue};
10 use crate::isl::isl_type::IslType;
11 use crate::isl::IslVersion;
12 use crate::result::IonSchemaResult;
13 use ion_rs::Element;
14
15 pub fn named_type<A: Into<String>, B: Into<Vec<IslConstraint>>>(
17 name: A,
18 constraints: B,
19 ) -> IslType {
20 let constraints = constraints.into();
21 IslType::new(Some(name.into()), constraints, None)
22 }
23
24 pub fn anonymous_type<A: Into<Vec<IslConstraint>>>(constraints: A) -> IslType {
26 let constraints = constraints.into();
27 let isl_constraints: Vec<IslConstraintValue> = constraints
28 .iter()
29 .map(|c| c.constraint_value.to_owned())
30 .collect();
31 IslType::new(None, constraints, None)
32 }
33
34 pub fn load_isl_type(bytes: &[u8]) -> IonSchemaResult<IslType> {
41 IslType::from_owned_element(IslVersion::V1_0, &Element::read_one(bytes)?, &mut vec![])
42 }
43}
44
45pub mod v_2_0 {
47 use crate::isl::isl_constraint::IslConstraint;
48 use crate::isl::isl_type::{v_1_0, IslType};
49 use crate::isl::IslVersion;
50 use crate::result::IonSchemaResult;
51 use ion_rs::Element;
52
53 pub fn named_type<A: Into<String>, B: Into<Vec<IslConstraint>>>(
55 name: A,
56 constraints: B,
57 ) -> IslType {
58 v_1_0::named_type(name, constraints)
59 }
60
61 pub fn anonymous_type<A: Into<Vec<IslConstraint>>>(constraints: A) -> IslType {
63 v_1_0::anonymous_type(constraints)
64 }
65
66 pub fn load_isl_type(bytes: &[u8]) -> IonSchemaResult<IslType> {
73 IslType::from_owned_element(IslVersion::V2_0, &Element::read_one(bytes)?, &mut vec![])
74 }
75}
76
77#[derive(Debug, Clone)]
81pub struct IslType {
82 name: Option<String>,
83 constraints: Vec<IslConstraint>,
84 pub(crate) isl_type_struct: Option<Element>,
87}
88
89impl IslType {
90 pub(crate) fn new(
91 name: Option<String>,
92 constraints: Vec<IslConstraint>,
93 isl_type_struct: Option<Element>,
94 ) -> Self {
95 Self {
96 name,
97 constraints,
98 isl_type_struct,
99 }
100 }
101
102 pub fn name(&self) -> Option<&str> {
103 self.name.as_deref()
104 }
105
106 pub fn constraints(&self) -> &[IslConstraint] {
107 &self.constraints
108 }
109
110 pub fn open_content(&self) -> Vec<(String, Element)> {
111 let mut open_content = vec![];
112 for constraint in &self.constraints {
113 if let IslConstraintValue::Unknown(constraint_name, element) =
114 &constraint.constraint_value
115 {
116 open_content.push((constraint_name.to_owned(), element.to_owned()))
117 }
118 }
119 open_content
120 }
121
122 pub(crate) fn is_open_content_allowed(&self) -> bool {
123 let mut open_content = true;
124 if self.constraints.contains(&IslConstraint::new(
125 IslVersion::V1_0,
126 IslConstraintValue::ContentClosed,
127 )) {
128 open_content = false;
129 }
130 open_content
131 }
132
133 pub(crate) fn from_owned_element(
135 isl_version: IslVersion,
136 ion: &Element,
137 inline_imported_types: &mut Vec<IslImportType>, ) -> IonSchemaResult<Self> {
139 let mut constraints = vec![];
140 let contains_annotations = ion.annotations().contains("type");
141
142 let ion_struct = try_to!(ion.as_struct());
143
144 if ion_struct.get_all("name").count() > 1 {
146 return Err(invalid_schema_error_raw(
147 "type definition must only contain a single field that represents name of the type",
148 ));
149 }
150 let type_name: Option<String> = match ion_struct.get("name") {
151 Some(name_element) => match name_element.as_symbol() {
152 Some(name_symbol) => match name_symbol.text() {
153 None => {
154 return Err(invalid_schema_error_raw(
155 "type names must be a symbol with defined text",
156 ))
157 }
158 Some(name) => {
159 if !name_element.annotations().is_empty() {
160 return Err(invalid_schema_error_raw(
161 "type names must be a non null and unannotated symbol with defined text",
162 ));
163 }
164 Some(name.to_owned())
165 }
166 },
167 None => {
168 return Err(invalid_schema_error_raw(
169 "type names must be a symbol with defined text",
170 ))
171 }
172 },
173 None => None, };
175
176 if !contains_annotations && type_name.is_some() {
177 return Err(invalid_schema_error_raw(
179 "Top level types must have `type::` annotation in their definition",
180 ));
181 }
182
183 let isl_type_name = match type_name.to_owned() {
185 Some(name) => name,
186 None => format!("{ion_struct:?}"),
187 };
188
189 for (field_name, value) in ion_struct.iter() {
191 let constraint_name = match field_name.text() {
192 Some("name") => continue, Some("occurs") => continue, Some(name) => name,
195 None => {
196 return Err(invalid_schema_error_raw(
197 "A type name symbol token does not have any text",
198 ))
199 }
200 };
201
202 let constraint = IslConstraint::new(
203 isl_version,
204 IslConstraintValue::from_ion_element(
205 isl_version,
206 constraint_name,
207 value,
208 &isl_type_name,
209 inline_imported_types,
210 )?,
211 );
212 constraints.push(constraint);
213 }
214 Ok(IslType::new(type_name, constraints, Some(ion.to_owned())))
215 }
216}
217
218impl WriteAsIon for IslType {
219 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
220 let mut struct_writer = writer.with_annotations(["type"])?.struct_writer()?;
221
222 if let Some(name) = self.name.as_ref() {
223 struct_writer
224 .field_writer("name")
225 .write_symbol(name.as_str())?;
226 }
227
228 for constraint in self.constraints() {
229 let constraint_name = constraint.constraint().field_name();
230 struct_writer
231 .field_writer(constraint_name)
232 .write(constraint.constraint())?;
233 }
234 struct_writer.close()
235 }
236}
237
238impl PartialEq for IslType {
241 fn eq(&self, other: &Self) -> bool {
242 self.constraints.len() == other.constraints.len()
243 && self.name == other.name
244 && self.constraints.iter().all(|constraint| {
245 other
246 .constraints
247 .iter()
248 .any(|other_constraint| constraint == other_constraint)
249 })
250 }
251}