1#![cfg_attr(docsrs, feature(doc_cfg))]
8mod schema {
16 pub mod shape_id;
17 pub mod shape_type;
18 pub mod trait_map;
19 pub mod trait_type;
20
21 pub mod prelude;
22 pub mod serde;
23}
24
25pub use schema::shape_id::ShapeId;
26pub use schema::shape_type::ShapeType;
27pub use schema::trait_map::TraitMap;
28pub use schema::trait_type::Trait;
29
30pub mod prelude {
31 pub use crate::schema::prelude::*;
32}
33
34pub mod serde {
35 pub use crate::schema::serde::*;
36}
37
38pub trait Schema: Send + Sync {
43 fn shape_id(&self) -> &ShapeId;
45
46 fn shape_type(&self) -> ShapeType;
48
49 fn traits(&self) -> &TraitMap;
51
52 fn member_name(&self) -> Option<&str> {
54 None
55 }
56
57 fn member_schema(&self, _name: &str) -> Option<&dyn Schema> {
59 None
60 }
61
62 fn member_schema_by_index(&self, _index: usize) -> Option<&dyn Schema> {
67 None
68 }
69
70 fn member(&self) -> Option<&dyn Schema> {
72 None
73 }
74
75 fn key(&self) -> Option<&dyn Schema> {
77 None
78 }
79
80 fn members(&self) -> Box<dyn Iterator<Item = &dyn Schema> + '_> {
82 Box::new(std::iter::empty())
83 }
84
85 fn member_index(&self) -> Option<usize> {
90 None
91 }
92}
93
94pub trait SchemaExt: Schema {
96 fn is_member(&self) -> bool {
98 self.shape_type().is_member()
99 }
100
101 fn is_structure(&self) -> bool {
103 self.shape_type() == ShapeType::Structure
104 }
105
106 fn is_union(&self) -> bool {
108 self.shape_type() == ShapeType::Union
109 }
110
111 fn is_list(&self) -> bool {
113 self.shape_type() == ShapeType::List
114 }
115
116 fn is_map(&self) -> bool {
118 self.shape_type() == ShapeType::Map
119 }
120
121 fn is_blob(&self) -> bool {
123 self.shape_type() == ShapeType::Blob
124 }
125
126 fn is_string(&self) -> bool {
128 self.shape_type() == ShapeType::String
129 }
130}
131
132impl<T: Schema + ?Sized> SchemaExt for T {}
133
134#[cfg(test)]
135mod test {
136 use crate::{Schema, SchemaExt, ShapeId, ShapeType, Trait, TraitMap};
137
138 #[derive(Debug)]
140 struct TestTrait {
141 id: ShapeId,
142 #[allow(dead_code)]
143 value: String,
144 }
145
146 impl Trait for TestTrait {
147 fn trait_id(&self) -> &ShapeId {
148 &self.id
149 }
150
151 fn as_any(&self) -> &dyn std::any::Any {
152 self
153 }
154 }
155
156 struct TestSchema {
158 id: ShapeId,
159 shape_type: ShapeType,
160 traits: TraitMap,
161 }
162
163 impl Schema for TestSchema {
164 fn shape_id(&self) -> &ShapeId {
165 &self.id
166 }
167
168 fn shape_type(&self) -> ShapeType {
169 self.shape_type
170 }
171
172 fn traits(&self) -> &TraitMap {
173 &self.traits
174 }
175 }
176
177 #[test]
178 fn test_shape_type_simple() {
179 assert!(ShapeType::String.is_simple());
180 assert!(ShapeType::Integer.is_simple());
181 assert!(ShapeType::Boolean.is_simple());
182 assert!(!ShapeType::Structure.is_simple());
183 assert!(!ShapeType::List.is_simple());
184 }
185
186 #[test]
187 fn test_shape_type_aggregate() {
188 assert!(ShapeType::Structure.is_aggregate());
189 assert!(ShapeType::Union.is_aggregate());
190 assert!(ShapeType::List.is_aggregate());
191 assert!(ShapeType::Map.is_aggregate());
192 assert!(!ShapeType::String.is_aggregate());
193 }
194
195 #[test]
196 fn test_shape_type_member() {
197 assert!(ShapeType::Member.is_member());
198 assert!(!ShapeType::String.is_member());
199 assert!(!ShapeType::Structure.is_member());
200 }
201
202 #[test]
203 fn test_shape_id_parsing() {
204 let id = ShapeId::new("smithy.api#String");
205 assert_eq!(id.namespace(), "smithy.api");
206 assert_eq!(id.shape_name(), "String");
207 assert_eq!(id.member_name(), None);
208 }
209
210 #[test]
211 fn test_shape_id_with_member() {
212 let id = ShapeId::new("com.example#MyStruct$member");
213 assert_eq!(id.namespace(), "com.example");
214 assert_eq!(id.shape_name(), "MyStruct");
215 assert_eq!(id.member_name(), Some("member"));
216 }
217
218 #[test]
219 fn test_trait_map() {
220 let mut map = TraitMap::new();
221 assert!(map.is_empty());
222 assert_eq!(map.len(), 0);
223
224 let trait_id = ShapeId::new("smithy.api#required");
225 let test_trait = Box::new(TestTrait {
226 id: trait_id.clone(),
227 value: "test".to_string(),
228 });
229
230 map.insert(test_trait);
231 assert!(!map.is_empty());
232 assert_eq!(map.len(), 1);
233 assert!(map.contains(&trait_id));
234
235 let retrieved = map.get(&trait_id);
236 assert!(retrieved.is_some());
237 }
238
239 #[test]
240 fn test_schema_ext() {
241 let schema = TestSchema {
242 id: ShapeId::new("com.example#MyStruct"),
243 shape_type: ShapeType::Structure,
244 traits: TraitMap::new(),
245 };
246
247 assert!(schema.is_structure());
248 assert!(!schema.is_union());
249 assert!(!schema.is_list());
250 assert!(!schema.is_member());
251 }
252
253 #[test]
254 fn test_schema_basic() {
255 let schema = TestSchema {
256 id: ShapeId::new("smithy.api#String"),
257 shape_type: ShapeType::String,
258 traits: TraitMap::new(),
259 };
260
261 assert_eq!(schema.shape_id().as_str(), "smithy.api#String");
262 assert_eq!(schema.shape_type(), ShapeType::String);
263 assert!(schema.traits().is_empty());
264 assert!(schema.member_name().is_none());
265 assert!(schema.member_schema("test").is_none());
266 assert!(schema.member_schema_by_index(0).is_none());
267 }
268}