1#[macro_export]
27macro_rules! setters {
28 (@single $(#[$meta:meta])* $name:ident : $typ:ty => $transform:expr) => {
29 #[allow(clippy::redundant_field_names)]
30 #[allow(clippy::needless_update)]
31 #[allow(missing_docs)]
32 #[must_use]
33 $(#[$meta])*
34 pub fn $name<P: ::std::convert::Into<$typ>>(self, $name: P) -> Self {
35 let $name: $typ = $name.into();
36 Self {
37 $name: $transform,
38 ..self
39 }
40 }
41 };
42 (@recurse) => {};
44 (@recurse $(#[$meta:meta])* $name:ident : $typ:ty, $($tokens:tt)*) => {
46 $crate::setters! { @recurse $(#[$meta])* $name: $typ => $name, $($tokens)* }
47 };
48 (@recurse $(#[$meta:meta])* $name:ident : $typ:ty => $transform:expr, $($tokens:tt)*) => {
50 $crate::setters! { @single $(#[$meta])* $name : $typ => $transform }
51 $crate::setters! { @recurse $($tokens)* }
52 };
53 ($($tokens:tt)*) => {
54 $crate::setters! { @recurse $($tokens)* }
55 }
56}
57
58#[macro_export]
124macro_rules! operation {
125 (@builder
127 $(#[$outer:meta])*
128 $name:ident<$($generic:ident: $first_constraint:ident $(+ $constraint:ident)* ),* $(+ $lt:lifetime)?>,
130 client: $client:ty,
132 @required
134 $($required:ident: $rtype:ty,)*
135 @optional
137 $($optional:ident: $otype:ty,)*
138 @nosetter
140 $($nosetter:ident: $nstype:ty),*
141 ) => {
142 azure_core::__private::paste! {
143 #[derive(Debug, Clone)]
144 $(#[$outer])*
145 pub struct [<$name Builder>]<$($generic)*> {
146 client: $client,
147 $($required: $rtype,)*
148 $($optional: Option<$otype>,)*
149 $($nosetter: Option<$nstype>,)*
150 context: azure_core::Context,
151 }
152
153 impl <$($generic: $first_constraint $(+ $constraint)* )*>[<$name Builder>]<$($generic),*> {
155 pub(crate) fn new(
156 client: $client,
157 $($required: $rtype,)*
158 ) -> Self {
159 Self {
160 client,
161 $($required,)*
162 $($optional: None,)*
163 $($nosetter: None,)*
164 context: azure_core::Context::new(),
165 }
166 }
167
168 $crate::setters! {
169 $($optional: $otype => Some($optional),)*
170 context: azure_core::Context => context,
171 }
172 }
173 }
174 };
175 (#[stream] $(#[$outer:meta])* $name:ident,
177 client: $client:ty,
178 $($required:ident: $rtype:ty,)*
179 $(?$optional:ident: $otype:ty),*) => {
180 $crate::operation!{
181 @builder
182 $(#[$outer])*
183 $name<>,
184 client: $client,
185 @required
186 $($required: $rtype,)*
187 @optional
188 $($optional: $otype,)*
189 @nosetter
190 }
191 };
192 (#[stream] $(#[$outer:meta])*
193 $name:ident,
194 client: $client:ty,
195 $($required:ident: $rtype:ty,)*
196 $(?$optional:ident: $otype:ty,)*
197 $(#[skip]$nosetter:ident: $nstype:ty),*
198 ) => {
199 $crate::operation!{
200 @builder
201 $(#[$outer])*
202 $name<>,
203 client: $client,
204 @required
205 $($required: $rtype,)*
206 @optional
207 $($optional: $otype,)*
208 @nosetter
209 $($nosetter: $nstype),*
210 }
211 };
212 ($(#[$outer:meta])* $name:ident<$($generic:ident: $first_constraint:ident $(+ $constraint:ident)* ),* $(+ $lt:lifetime)?>,
214 client: $client:ty,
215 @required
216 $($required:ident: $rtype:ty,)*
217 @optional
218 $($optional:ident: $otype:ty,)*
219 @nosetter
220 $($nosetter:ident: $nstype:ty),*
221 ) => {
222 $crate::operation! {
223 @builder
224 $(#[$outer])*
225 $name<$($generic: $first_constraint $(+ $constraint)*),* $(+ $lt)*>,
226 client: $client,
227 @required
228 $($required: $rtype,)*
229 @optional
230 $($optional: $otype,)*
231 @nosetter
232 $($nosetter: $nstype),*
233 }
234 $crate::future!($name);
235 azure_core::__private::paste! {
236 impl <$($generic: $first_constraint $(+ $constraint)*)* $(+ $lt)*> std::future::IntoFuture for [<$name Builder>]<$($generic),*> {
237 type IntoFuture = $name;
238 type Output = <$name as std::future::Future>::Output;
239 fn into_future(self) -> Self::IntoFuture {
240 Self::into_future(self)
241 }
242 }
243 }
244 };
245 ($(#[$outer:meta])* $name:ident,
247 client: $client:ty,
248 $($required:ident: $rtype:ty,)*
249 $(?$optional:ident: $otype:ty),*) => {
250 $crate::operation!{
251 $(#[$outer])*
252 $name<>,
253 client: $client,
254 @required
255 $($required: $rtype,)*
256 @optional
257 $($optional: $otype,)*
258 @nosetter
259 }
260 };
261 ($(#[$outer:meta])* $name:ident<$($generic:ident: $first_constraint:ident $(+ $constraint:ident)*),* $(+ $lt:lifetime)?>,
263 client: $client:ty,
264 $($required:ident: $rtype:ty,)*
265 $(?$optional:ident: $otype:ty,)*
266 $(#[skip] $nosetter:ident: $nstype:ty),*) => {
267 $crate::operation!{
268 $(#[$outer])*
269 $name<$($generic: $first_constraint $(+ $constraint)*),* $(+ $lt)*>,
270 client: $client,
271 @required
272 $($required: $rtype,)*
273 @optional
274 $($optional: $otype,)*
275 @nosetter
276 $($nosetter: $nstype),*
277 }
278 }
279}
280
281#[macro_export]
286macro_rules! future {
287 ($name:ident) => {
288 $crate::future!($name<>);
289 };
290 ($name:ident<$($generic:ident)?>) => {
291 azure_core::__private::paste! {
292 #[cfg(target_arch = "wasm32")]
293 pub type $name<$($generic)*> =
294 std::pin::Pin<std::boxed::Box<dyn std::future::Future<Output = azure_core::Result<[<$name Response>]<$($generic)*>>> + 'static>>;
295 #[cfg(not(target_arch = "wasm32"))]
296 pub type $name<$($generic)*> =
297 futures::future::BoxFuture<'static, azure_core::Result<[<$name Response>]<$($generic)*>>>;
298 }
299 };
300}
301
302#[macro_export]
312macro_rules! request_header {
313 ($(#[$outer:meta])* $name:ident, $header:ident) => {
314 $crate::request_header!($name, $header,);
315 };
316 ($(#[$outer:meta])* $name:ident, $header:ident, $(($variant:ident, $value:expr)), *) => {
317 $crate::request_option!($(#[$outer])* $name);
318 impl $name {
319 $(
320 pub const $variant: $name = $name::from_static($value);
321 )*
322 }
323 impl $crate::headers::Header for $name {
324 fn name(&self) -> $crate::headers::HeaderName {
325 $crate::headers::$header
326 }
327
328 fn value(&self) -> $crate::headers::HeaderValue {
329 $crate::headers::HeaderValue::from_cow(self.0.clone())
330 }
331 }
332 };
333}
334
335#[macro_export]
342macro_rules! request_query {
343 ($(#[$outer:meta])* $name:ident, $option:expr) => {
344 $crate::request_option!($(#[$outer])* $name);
345 impl $crate::AppendToUrlQuery for $name {
346 fn append_to_url_query(&self, url: &mut $crate::Url) {
347 url.query_pairs_mut().append_pair($option, &self.0);
348 }
349 }
350 };
351}
352
353#[macro_export]
360macro_rules! request_option {
361 ($(#[$outer:meta])* $name:ident) => {
362 #[derive(Debug, Clone)]
363 $(#[$outer])*
364 pub struct $name(std::borrow::Cow<'static, str>);
365
366 impl $name {
367 pub fn new<S>(s: S) -> Self
368 where
369 S: Into<std::borrow::Cow<'static, str>>,
370 {
371 Self(s.into())
372 }
373
374 pub const fn from_static(s: &'static str) -> Self {
375 Self(std::borrow::Cow::Borrowed(s))
376 }
377 }
378
379 impl<S> From<S> for $name
380 where
381 S: Into<std::borrow::Cow<'static, str>>,
382 {
383 fn from(s: S) -> Self {
384 Self::new(s)
385 }
386 }
387 };
388}
389
390#[macro_export]
397macro_rules! create_enum {
398 ($name:ident, $(($variant:ident, $value:expr)), *) => (
399 #[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]
400 pub enum $name {
401 $(
402 $variant,
403 )*
404 }
405
406 impl ::std::convert::From<$name> for &'static str {
407 fn from(e: $name) -> Self {
408 match e {
409 $(
410 $name::$variant => $value,
411 )*
412 }
413 }
414 }
415
416 impl $crate::parsing::FromStringOptional<$name> for $name {
417 fn from_str_optional(s : &str) -> $crate::error::Result<$name> {
418 s.parse::<$name>()
419 }
420 }
421
422 impl ::std::str::FromStr for $name {
423 type Err = $crate::error::Error;
424
425 fn from_str(s: &str) -> $crate::error::Result<$name> {
426 match s {
427 $(
428 $value => Ok($name::$variant),
429 )*
430 _ => Err($crate::error::Error::with_message($crate::error::ErrorKind::DataConversion, || format!("unknown variant of {} found: \"{}\"",
431 stringify!($name),
432 s
433 )))
434 }
435 }
436 }
437
438 impl<'de> serde::Deserialize<'de> for $name {
439 fn deserialize<D>(deserializer: D) -> ::core::result::Result<Self, D::Error>
440 where
441 D: serde::Deserializer<'de>,
442 {
443 let s = String::deserialize(deserializer)?;
444
445 match s.as_ref() {
446 $(
447 $value => Ok(Self::$variant),
448 )*
449 _ => Err(serde::de::Error::custom("unsupported value")),
450 }
451 }
452 }
453
454 impl serde::Serialize for $name {
455 fn serialize<S>(&self, s: S) -> ::core::result::Result<S::Ok, S::Error>
456 where S: serde::Serializer {
457 return s.serialize_str(&self.to_string())
458 }
459 }
460
461 impl ::std::convert::AsRef<str> for $name {
462 fn as_ref(&self) -> &str {
463 match *self {
464 $(
465 $name::$variant => $value,
466 )*
467 }
468 }
469 }
470
471 impl ::std::fmt::Display for $name {
472 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
473 match *self {
474 $(
475 $name::$variant => write!(f, "{}", $value),
476 )*
477 }
478 }
479 }
480 )
481}
482
483#[macro_export]
487macro_rules! static_url {
488 ( $(#[$outer:meta])* $name:ident, $value:expr) => {
489 $(#[$outer])*
490 pub static $name: once_cell::sync::Lazy<$crate::Url> = once_cell::sync::Lazy::new(|| {
491 $crate::Url::parse($value).expect("hardcoded URL must parse")
492 });
493 };
494}
495
496#[cfg(test)]
497mod test {
498 create_enum!(Colors, (Black, "Black"), (White, "White"), (Red, "Red"));
499 create_enum!(ColorsMonochrome, (Black, "Black"), (White, "White"));
500
501 struct Options {
502 a: Option<String>,
503 b: u32,
504 }
505
506 #[allow(dead_code)]
507 impl Options {
508 setters! {
509 a: String => Some(a),
510 b: u32 => b,
511 }
512 }
513
514 impl Default for Options {
515 fn default() -> Self {
516 Options { a: None, b: 1 }
517 }
518 }
519
520 #[test]
521 fn test_color_parse_1() {
522 let color = "Black".parse::<Colors>().unwrap();
523 assert_eq!(Colors::Black, color);
524 }
525
526 #[test]
527 fn test_color_parse_2() {
528 let color = "White".parse::<ColorsMonochrome>().unwrap();
529 assert_eq!(ColorsMonochrome::White, color);
530 }
531
532 #[test]
533 fn test_color_parse_err_1() {
534 "Red".parse::<ColorsMonochrome>().unwrap_err();
535 }
536
537 #[test]
538 fn test_setters() {
539 let options = Options::default().a("test".to_owned());
540
541 assert_eq!(Some("test".to_owned()), options.a);
542 assert_eq!(1, options.b);
543 }
544}