aws_smithy_schema/schema/
traits.rs1use crate::{ShapeId, Trait};
13use std::any::Any;
14
15macro_rules! annotation_trait {
16 ($(#[$meta:meta])* $name:ident, $ns:literal, $trait_name:literal) => {
17 $(#[$meta])*
18 #[derive(Debug, Clone)]
19 #[allow(dead_code)] pub struct $name;
21
22 impl $name {
23 pub const TRAIT_ID: ShapeId = crate::shape_id!($ns, $trait_name);
25 }
26
27 impl Trait for $name {
28 fn trait_id(&self) -> &ShapeId { &Self::TRAIT_ID }
29 fn as_any(&self) -> &dyn Any { self }
30 }
31 };
32}
33
34macro_rules! string_trait {
35 ($(#[$meta:meta])* $name:ident, $ns:literal, $trait_name:literal) => {
36 $(#[$meta])*
37 #[derive(Debug, Clone)]
38 #[allow(dead_code)] pub struct $name {
40 value: &'static str,
41 }
42
43 #[allow(dead_code)] impl $name {
45 pub const TRAIT_ID: ShapeId = crate::shape_id!($ns, $trait_name);
47
48 pub const fn new(value: &'static str) -> Self {
50 Self { value }
51 }
52
53 pub fn value(&self) -> &str {
55 self.value
56 }
57 }
58
59 impl Trait for $name {
60 fn trait_id(&self) -> &ShapeId { &Self::TRAIT_ID }
61 fn as_any(&self) -> &dyn Any { self }
62 }
63 };
64}
65
66string_trait!(
69 JsonNameTrait,
71 "smithy.api", "jsonName"
72);
73
74string_trait!(
75 XmlNameTrait,
77 "smithy.api", "xmlName"
78);
79
80string_trait!(
81 MediaTypeTrait,
83 "smithy.api", "mediaType"
84);
85
86annotation_trait!(
87 XmlAttributeTrait,
89 "smithy.api", "xmlAttribute"
90);
91
92annotation_trait!(
93 XmlFlattenedTrait,
95 "smithy.api", "xmlFlattened"
96);
97
98annotation_trait!(
101 XmlNamespaceTrait,
103 "smithy.api", "xmlNamespace"
104);
105
106#[derive(Debug, Clone, Copy)]
110#[allow(dead_code)] pub struct TimestampFormatTrait {
112 format: TimestampFormat,
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub enum TimestampFormat {
118 EpochSeconds,
120 DateTime,
122 HttpDate,
124}
125
126#[allow(dead_code)] impl TimestampFormatTrait {
128 pub const TRAIT_ID: ShapeId = crate::shape_id!("smithy.api", "timestampFormat");
130
131 pub const fn new(format: TimestampFormat) -> Self {
133 Self { format }
134 }
135
136 pub fn format(&self) -> TimestampFormat {
138 self.format
139 }
140}
141
142impl Trait for TimestampFormatTrait {
143 fn trait_id(&self) -> &ShapeId {
144 &Self::TRAIT_ID
145 }
146 fn as_any(&self) -> &dyn Any {
147 self
148 }
149}
150
151string_trait!(
154 HttpHeaderTrait,
156 "smithy.api", "httpHeader"
157);
158
159string_trait!(
160 HttpQueryTrait,
162 "smithy.api", "httpQuery"
163);
164
165string_trait!(
166 HttpPrefixHeadersTrait,
168 "smithy.api", "httpPrefixHeaders"
169);
170
171annotation_trait!(
172 HttpLabelTrait,
174 "smithy.api", "httpLabel"
175);
176
177annotation_trait!(
178 HttpPayloadTrait,
180 "smithy.api", "httpPayload"
181);
182
183annotation_trait!(
184 HttpQueryParamsTrait,
186 "smithy.api", "httpQueryParams"
187);
188
189annotation_trait!(
190 HttpResponseCodeTrait,
192 "smithy.api", "httpResponseCode"
193);
194
195#[derive(Debug, Clone)]
204pub struct HttpTrait {
205 method: &'static str,
206 uri: &'static str,
207 code: u16,
208}
209
210impl HttpTrait {
211 pub const fn new(method: &'static str, uri: &'static str, code: Option<u16>) -> Self {
213 Self {
214 method,
215 uri,
216 code: match code {
217 Some(c) => c,
218 None => 200,
219 },
220 }
221 }
222
223 pub fn method(&self) -> &str {
225 self.method
226 }
227
228 pub fn uri(&self) -> &str {
234 self.uri
235 }
236
237 pub fn code(&self) -> u16 {
239 self.code
240 }
241}
242
243annotation_trait!(
246 StreamingTrait,
248 "smithy.api", "streaming"
249);
250
251annotation_trait!(
252 EventHeaderTrait,
254 "smithy.api", "eventHeader"
255);
256
257annotation_trait!(
258 EventPayloadTrait,
260 "smithy.api", "eventPayload"
261);
262
263annotation_trait!(
266 SensitiveTrait,
268 "smithy.api", "sensitive"
269);
270
271annotation_trait!(
274 HostLabelTrait,
276 "smithy.api", "hostLabel"
277);
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282
283 #[test]
284 fn downcast_json_name() {
285 let t: Box<dyn Trait> = Box::new(JsonNameTrait::new("userName"));
286 assert_eq!(t.trait_id().as_str(), "smithy.api#jsonName");
287 let json_name = t.as_any().downcast_ref::<JsonNameTrait>().unwrap();
288 assert_eq!(json_name.value(), "userName");
289 }
290
291 #[test]
292 fn downcast_sensitive() {
293 let t: Box<dyn Trait> = Box::new(SensitiveTrait);
294 assert_eq!(t.trait_id().as_str(), "smithy.api#sensitive");
295 assert!(t.as_any().downcast_ref::<SensitiveTrait>().is_some());
296 }
297
298 #[test]
299 fn timestamp_format_parsing() {
300 let t = TimestampFormatTrait::new(TimestampFormat::EpochSeconds);
301 assert_eq!(t.format(), TimestampFormat::EpochSeconds);
302 assert_eq!(t.trait_id().as_str(), "smithy.api#timestampFormat");
303 }
304}