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}