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 pub mod traits;
21
22 pub mod codec;
23 pub mod header_omit_settings;
24 pub mod http_protocol;
25 pub mod prelude;
26 pub mod protocol;
27 pub mod serde;
28}
29
30pub use schema::shape_id::ShapeId;
31pub use schema::shape_type::ShapeType;
32pub use schema::trait_map::TraitMap;
33pub use schema::trait_type::Trait;
34pub use schema::trait_type::{AnnotationTrait, DocumentTrait, StringTrait};
35
36pub mod prelude {
37 pub use crate::schema::prelude::*;
38}
39
40pub mod serde {
41 pub use crate::schema::serde::*;
42}
43
44pub mod traits {
45 pub use crate::schema::traits::*;
46}
47
48pub mod codec {
49 pub use crate::schema::codec::*;
50}
51
52pub mod header_omit_settings {
53 pub use crate::schema::header_omit_settings::*;
54}
55
56pub mod protocol {
57 pub use crate::schema::protocol::*;
58}
59
60pub mod http_protocol {
61 pub use crate::schema::http_protocol::*;
62}
63
64use schema::traits as trait_types;
73
74#[derive(Debug)]
75pub struct Schema {
76 id: ShapeId,
77 shape_type: ShapeType,
78 member_name: Option<&'static str>,
80 member_index: Option<usize>,
82 members: SchemaMembers,
84
85 original_name: Option<&'static str>,
100
101 sensitive: Option<trait_types::SensitiveTrait>,
106 json_name: Option<trait_types::JsonNameTrait>,
107 timestamp_format: Option<trait_types::TimestampFormatTrait>,
108 xml_name: Option<trait_types::XmlNameTrait>,
109 xml_attribute: Option<trait_types::XmlAttributeTrait>,
110 xml_flattened: Option<trait_types::XmlFlattenedTrait>,
111 xml_unwrapped_output: bool,
117 has_body_members: bool,
131 xml_namespace: Option<trait_types::XmlNamespaceTrait>,
132 http_header: Option<trait_types::HttpHeaderTrait>,
133 http_label: Option<trait_types::HttpLabelTrait>,
134 http_payload: Option<trait_types::HttpPayloadTrait>,
135 http_prefix_headers: Option<trait_types::HttpPrefixHeadersTrait>,
136 http_query: Option<trait_types::HttpQueryTrait>,
137 http_query_params: Option<trait_types::HttpQueryParamsTrait>,
138 http_response_code: Option<trait_types::HttpResponseCodeTrait>,
139 http: Option<trait_types::HttpTrait>,
142 streaming: Option<trait_types::StreamingTrait>,
143 event_header: Option<trait_types::EventHeaderTrait>,
144 event_payload: Option<trait_types::EventPayloadTrait>,
145 host_label: Option<trait_types::HostLabelTrait>,
146 media_type: Option<trait_types::MediaTypeTrait>,
147
148 traits: Option<&'static std::sync::LazyLock<TraitMap>>,
150}
151
152#[derive(Debug)]
154enum SchemaMembers {
155 None,
157 Struct { members: &'static [&'static Schema] },
159 List { member: &'static Schema },
161 Map {
163 key: &'static Schema,
164 value: &'static Schema,
165 },
166}
167
168impl Schema {
169 const EMPTY_TRAITS: Self = Self {
171 id: ShapeId::from_static("", "", ""),
172 shape_type: ShapeType::Boolean,
173 member_name: None,
174 member_index: None,
175 members: SchemaMembers::None,
176 original_name: None,
177 sensitive: None,
178 json_name: None,
179 timestamp_format: None,
180 xml_name: None,
181 xml_attribute: None,
182 xml_flattened: None,
183 xml_unwrapped_output: false,
184 has_body_members: true,
185 xml_namespace: None,
186 http_header: None,
187 http_label: None,
188 http_payload: None,
189 http_prefix_headers: None,
190 http_query: None,
191 http_query_params: None,
192 http_response_code: None,
193 http: None,
194 streaming: None,
195 event_header: None,
196 event_payload: None,
197 host_label: None,
198 media_type: None,
199 traits: None,
200 };
201
202 pub const fn new(id: ShapeId, shape_type: ShapeType) -> Self {
204 Self {
205 id,
206 shape_type,
207 ..Self::EMPTY_TRAITS
208 }
209 }
210
211 pub const fn new_struct(
213 id: ShapeId,
214 shape_type: ShapeType,
215 members: &'static [&'static Schema],
216 ) -> Self {
217 Self {
218 id,
219 shape_type,
220 members: SchemaMembers::Struct { members },
221 ..Self::EMPTY_TRAITS
222 }
223 }
224
225 pub const fn new_list(id: ShapeId, member: &'static Schema) -> Self {
227 Self {
228 id,
229 shape_type: ShapeType::List,
230 members: SchemaMembers::List { member },
231 ..Self::EMPTY_TRAITS
232 }
233 }
234
235 pub const fn new_map(id: ShapeId, key: &'static Schema, value: &'static Schema) -> Self {
237 Self {
238 id,
239 shape_type: ShapeType::Map,
240 members: SchemaMembers::Map { key, value },
241 ..Self::EMPTY_TRAITS
242 }
243 }
244
245 pub const fn new_member(
247 id: ShapeId,
248 shape_type: ShapeType,
249 member_name: &'static str,
250 member_index: usize,
251 ) -> Self {
252 Self {
253 id,
254 shape_type,
255 member_name: Some(member_name),
256 member_index: Some(member_index),
257 ..Self::EMPTY_TRAITS
258 }
259 }
260
261 pub fn shape_id(&self) -> &ShapeId {
263 &self.id
264 }
265
266 pub fn shape_type(&self) -> ShapeType {
268 self.shape_type
269 }
270
271 pub fn traits(&self) -> Option<&TraitMap> {
273 self.traits.map(|lazy| &**lazy)
274 }
275
276 pub fn sensitive(&self) -> Option<&trait_types::SensitiveTrait> {
280 self.sensitive.as_ref()
281 }
282
283 pub fn json_name(&self) -> Option<&trait_types::JsonNameTrait> {
285 self.json_name.as_ref()
286 }
287
288 pub fn timestamp_format(&self) -> Option<&trait_types::TimestampFormatTrait> {
290 self.timestamp_format.as_ref()
291 }
292
293 pub fn xml_name(&self) -> Option<&trait_types::XmlNameTrait> {
295 self.xml_name.as_ref()
296 }
297
298 pub fn xml_namespace(&self) -> Option<&trait_types::XmlNamespaceTrait> {
300 self.xml_namespace.as_ref()
301 }
302
303 pub fn xml_attribute(&self) -> bool {
305 self.xml_attribute.is_some()
306 }
307
308 pub fn xml_flattened(&self) -> bool {
310 self.xml_flattened.is_some()
311 }
312
313 pub fn xml_unwrapped_output(&self) -> bool {
316 self.xml_unwrapped_output
317 }
318
319 pub fn has_body_members(&self) -> bool {
322 self.has_body_members
323 }
324
325 pub fn has_http_response_binding(&self) -> bool {
329 self.http_header.is_some()
330 || self.http_response_code.is_some()
331 || self.http_prefix_headers.is_some()
332 || self.http_payload.is_some()
333 }
334
335 pub fn http_header(&self) -> Option<&trait_types::HttpHeaderTrait> {
336 self.http_header.as_ref()
337 }
338
339 pub fn http_query(&self) -> Option<&trait_types::HttpQueryTrait> {
341 self.http_query.as_ref()
342 }
343
344 pub fn http_label(&self) -> Option<&trait_types::HttpLabelTrait> {
346 self.http_label.as_ref()
347 }
348
349 pub fn http_payload(&self) -> Option<&trait_types::HttpPayloadTrait> {
351 self.http_payload.as_ref()
352 }
353
354 pub fn http_prefix_headers(&self) -> Option<&trait_types::HttpPrefixHeadersTrait> {
356 self.http_prefix_headers.as_ref()
357 }
358
359 pub fn media_type(&self) -> Option<&trait_types::MediaTypeTrait> {
361 self.media_type.as_ref()
362 }
363
364 pub fn http_query_params(&self) -> Option<&trait_types::HttpQueryParamsTrait> {
366 self.http_query_params.as_ref()
367 }
368
369 pub fn http_response_code(&self) -> Option<&trait_types::HttpResponseCodeTrait> {
371 self.http_response_code.as_ref()
372 }
373
374 pub fn http(&self) -> Option<&trait_types::HttpTrait> {
379 self.http.as_ref()
380 }
381
382 pub const fn with_original_name(mut self, name: &'static str) -> Self {
387 self.original_name = Some(name);
388 self
389 }
390
391 pub const fn with_map_members(mut self, key: &'static Schema, value: &'static Schema) -> Self {
394 self.members = SchemaMembers::Map { key, value };
395 self
396 }
397
398 pub const fn with_list_member(mut self, member: &'static Schema) -> Self {
400 self.members = SchemaMembers::List { member };
401 self
402 }
403
404 pub const fn with_sensitive(mut self) -> Self {
406 self.sensitive = Some(trait_types::SensitiveTrait);
407 self
408 }
409
410 pub const fn with_json_name(mut self, value: &'static str) -> Self {
412 self.json_name = Some(trait_types::JsonNameTrait::new(value));
413 self
414 }
415
416 pub const fn with_timestamp_format(mut self, format: trait_types::TimestampFormat) -> Self {
418 self.timestamp_format = Some(trait_types::TimestampFormatTrait::new(format));
419 self
420 }
421
422 pub const fn with_xml_name(mut self, value: &'static str) -> Self {
424 self.xml_name = Some(trait_types::XmlNameTrait::new(value));
425 self
426 }
427
428 pub const fn with_xml_attribute(mut self) -> Self {
430 self.xml_attribute = Some(trait_types::XmlAttributeTrait);
431 self
432 }
433
434 pub const fn with_xml_flattened(mut self) -> Self {
436 self.xml_flattened = Some(trait_types::XmlFlattenedTrait);
437 self
438 }
439
440 pub const fn with_xml_unwrapped_output(mut self) -> Self {
442 self.xml_unwrapped_output = true;
443 self
444 }
445
446 pub const fn with_no_body_members(mut self) -> Self {
449 self.has_body_members = false;
450 self
451 }
452
453 pub const fn with_http_header(mut self, value: &'static str) -> Self {
455 self.http_header = Some(trait_types::HttpHeaderTrait::new(value));
456 self
457 }
458
459 pub const fn with_http_label(mut self) -> Self {
461 self.http_label = Some(trait_types::HttpLabelTrait);
462 self
463 }
464
465 pub const fn with_http_payload(mut self) -> Self {
467 self.http_payload = Some(trait_types::HttpPayloadTrait);
468 self
469 }
470
471 pub const fn with_http_prefix_headers(mut self, value: &'static str) -> Self {
473 self.http_prefix_headers = Some(trait_types::HttpPrefixHeadersTrait::new(value));
474 self
475 }
476
477 pub const fn with_http_query(mut self, value: &'static str) -> Self {
479 self.http_query = Some(trait_types::HttpQueryTrait::new(value));
480 self
481 }
482
483 pub const fn with_http_query_params(mut self) -> Self {
485 self.http_query_params = Some(trait_types::HttpQueryParamsTrait);
486 self
487 }
488
489 pub const fn with_http_response_code(mut self) -> Self {
491 self.http_response_code = Some(trait_types::HttpResponseCodeTrait);
492 self
493 }
494
495 pub const fn with_http(mut self, http: trait_types::HttpTrait) -> Self {
497 self.http = Some(http);
498 self
499 }
500
501 pub const fn with_streaming(mut self) -> Self {
503 self.streaming = Some(trait_types::StreamingTrait);
504 self
505 }
506
507 pub const fn with_event_header(mut self) -> Self {
509 self.event_header = Some(trait_types::EventHeaderTrait);
510 self
511 }
512
513 pub const fn with_event_payload(mut self) -> Self {
515 self.event_payload = Some(trait_types::EventPayloadTrait);
516 self
517 }
518
519 pub const fn with_host_label(mut self) -> Self {
521 self.host_label = Some(trait_types::HostLabelTrait);
522 self
523 }
524
525 pub const fn with_media_type(mut self, value: &'static str) -> Self {
527 self.media_type = Some(trait_types::MediaTypeTrait::new(value));
528 self
529 }
530
531 pub const fn with_xml_namespace(
537 mut self,
538 uri: &'static str,
539 prefix: Option<&'static str>,
540 ) -> Self {
541 self.xml_namespace = Some(trait_types::XmlNamespaceTrait::new(uri, prefix));
542 self
543 }
544
545 pub const fn with_traits(mut self, traits: &'static std::sync::LazyLock<TraitMap>) -> Self {
547 self.traits = Some(traits);
548 self
549 }
550
551 pub fn member_name(&self) -> Option<&'static str> {
557 self.member_name
558 }
559
560 pub fn member_index(&self) -> Option<usize> {
565 self.member_index
566 }
567
568 pub fn original_name(&self) -> Option<&str> {
574 self.original_name
575 }
576
577 pub fn member_schema(&self, name: &str) -> Option<&Schema> {
579 match &self.members {
580 SchemaMembers::Struct { members } => members
581 .iter()
582 .find(|m| m.member_name == Some(name))
583 .copied(),
584 _ => None,
585 }
586 }
587
588 pub fn member_schema_by_index(&self, index: usize) -> Option<&Schema> {
593 match &self.members {
594 SchemaMembers::Struct { members } => members.get(index).copied(),
595 _ => None,
596 }
597 }
598
599 pub fn members(&self) -> &[&Schema] {
601 match &self.members {
602 SchemaMembers::Struct { members } => members,
603 _ => &[],
604 }
605 }
606
607 pub fn member(&self) -> Option<&Schema> {
609 match &self.members {
610 SchemaMembers::List { member } => Some(member),
611 SchemaMembers::Map { value, .. } => Some(value),
612 _ => None,
613 }
614 }
615
616 pub fn member_static(&self) -> Option<&'static Schema> {
621 match &self.members {
622 SchemaMembers::List { member } => Some(*member),
623 SchemaMembers::Map { value, .. } => Some(*value),
624 _ => None,
625 }
626 }
627
628 pub fn key(&self) -> Option<&Schema> {
630 match &self.members {
631 SchemaMembers::Map { key, .. } => Some(key),
632 _ => None,
633 }
634 }
635
636 pub fn key_static(&self) -> Option<&'static Schema> {
639 match &self.members {
640 SchemaMembers::Map { key, .. } => Some(*key),
641 _ => None,
642 }
643 }
644
645 pub fn is_member(&self) -> bool {
649 self.shape_type.is_member()
650 }
651
652 pub fn is_structure(&self) -> bool {
654 self.shape_type == ShapeType::Structure
655 }
656
657 pub fn is_union(&self) -> bool {
659 self.shape_type == ShapeType::Union
660 }
661
662 pub fn is_list(&self) -> bool {
664 self.shape_type == ShapeType::List
665 }
666
667 pub fn is_map(&self) -> bool {
669 self.shape_type == ShapeType::Map
670 }
671
672 pub fn is_blob(&self) -> bool {
674 self.shape_type == ShapeType::Blob
675 }
676
677 pub fn is_string(&self) -> bool {
679 self.shape_type == ShapeType::String
680 }
681}
682
683#[cfg(test)]
684mod test {
685 use crate::{shape_id, Schema, ShapeType, Trait, TraitMap};
686
687 #[derive(Debug)]
689 struct TestTrait {
690 id: crate::ShapeId,
691 #[allow(dead_code)]
692 value: String,
693 }
694
695 impl Trait for TestTrait {
696 fn trait_id(&self) -> &crate::ShapeId {
697 &self.id
698 }
699
700 fn as_any(&self) -> &dyn std::any::Any {
701 self
702 }
703 }
704
705 #[test]
706 fn test_shape_type_simple() {
707 assert!(ShapeType::String.is_simple());
708 assert!(ShapeType::Integer.is_simple());
709 assert!(ShapeType::Boolean.is_simple());
710 assert!(!ShapeType::Structure.is_simple());
711 assert!(!ShapeType::List.is_simple());
712 }
713
714 #[test]
715 fn test_shape_type_aggregate() {
716 assert!(ShapeType::Structure.is_aggregate());
717 assert!(ShapeType::Union.is_aggregate());
718 assert!(ShapeType::List.is_aggregate());
719 assert!(ShapeType::Map.is_aggregate());
720 assert!(!ShapeType::String.is_aggregate());
721 }
722
723 #[test]
724 fn test_shape_type_member() {
725 assert!(ShapeType::Member.is_member());
726 assert!(!ShapeType::String.is_member());
727 assert!(!ShapeType::Structure.is_member());
728 }
729
730 #[test]
731 fn test_shape_id_parsing() {
732 let id = shape_id!("smithy.api", "String");
733 assert_eq!(id.namespace(), "smithy.api");
734 assert_eq!(id.shape_name(), "String");
735 assert_eq!(id.member_name(), None);
736 }
737
738 #[test]
739 fn test_shape_id_with_member() {
740 let id = shape_id!("com.example", "MyStruct", "member");
741 assert_eq!(id.namespace(), "com.example");
742 assert_eq!(id.shape_name(), "MyStruct");
743 assert_eq!(id.member_name(), Some("member"));
744 }
745
746 #[test]
747 fn test_trait_map() {
748 let mut map = TraitMap::new();
749 assert!(map.is_empty());
750 assert_eq!(map.len(), 0);
751
752 let trait_id = shape_id!("smithy.api", "required");
753 let test_trait = Box::new(TestTrait {
754 id: trait_id,
755 value: "test".to_string(),
756 });
757
758 map.insert(test_trait);
759 assert!(!map.is_empty());
760 assert_eq!(map.len(), 1);
761 assert!(map.contains(&trait_id));
762
763 let retrieved = map.get(&trait_id);
764 assert!(retrieved.is_some());
765 }
766
767 #[test]
768 fn test_schema_predicates() {
769 let schema = Schema::new(shape_id!("com.example", "MyStruct"), ShapeType::Structure);
770
771 assert!(schema.is_structure());
772 assert!(!schema.is_union());
773 assert!(!schema.is_list());
774 assert!(!schema.is_member());
775 }
776
777 #[test]
778 fn test_schema_basic() {
779 let schema = Schema::new(shape_id!("smithy.api", "String"), ShapeType::String);
780
781 assert_eq!(schema.shape_id().as_str(), "smithy.api#String");
782 assert_eq!(schema.shape_type(), ShapeType::String);
783 assert!(schema.traits().is_none());
784 assert!(schema.member_name().is_none());
785 assert!(schema.member_schema("test").is_none());
786 assert!(schema.member_schema_by_index(0).is_none());
787 }
788}