Skip to main content

pulumi_gestalt_rust/
pulumi_any.rs

1use pulumi_gestalt_model::ToPulumiValue;
2
3pub type PulumiAny = pulumi_gestalt_model::PulumiValueMiddleware;
4
5/// Construct a [`PulumiAny`] value from JSON-like literals.
6///
7/// The syntax supports nested arrays/objects, trailing commas,
8/// and values implementing [`pulumi_gestalt_model::ToPulumiValue`].
9#[macro_export]
10macro_rules! pulumi_any {
11    ($($tt:tt)+) => {
12        $crate::pulumi_any_v2_internal!($($tt)+)
13    };
14}
15
16#[doc(hidden)]
17#[macro_export]
18macro_rules! pulumi_any_v2_internal {
19    (null) => {
20        $crate::__private::pulumi_gestalt_model::__private::pulumi_value_middleware(
21            $crate::__private::pulumi_gestalt_model::PulumiValueContent::None,
22        )
23    };
24    ([$($tt:tt)*]) => {
25        $crate::pulumi_any_v2_internal_array!([] $($tt)*)
26    };
27    ({$($tt:tt)*}) => {
28        $crate::pulumi_any_v2_internal_object!([] $($tt)*)
29    };
30    ($other:expr) => {
31        $crate::__private::pulumi_gestalt_model::__private::to_pulumi_value_middleware($other)
32    };
33}
34
35#[doc(hidden)]
36#[macro_export]
37macro_rules! pulumi_any_v2_internal_array {
38    ([$($elems:expr,)*]) => {
39        $crate::__private::pulumi_gestalt_model::__private::pulumi_value_middleware_array(
40            vec![$($elems,)*]
41        )
42    };
43    ([$($elems:expr,)*] , $($rest:tt)*) => {
44        $crate::pulumi_any_v2_internal_array!([$($elems,)*] $($rest)*)
45    };
46    ([$($elems:expr,)*] null , $($rest:tt)*) => {
47        $crate::pulumi_any_v2_internal_array!(
48            [
49                $($elems,)*
50                $crate::pulumi_any_v2_internal!(null),
51            ]
52            $($rest)*
53        )
54    };
55    ([$($elems:expr,)*] [$($inner:tt)*] , $($rest:tt)*) => {
56        $crate::pulumi_any_v2_internal_array!(
57            [
58                $($elems,)*
59                $crate::pulumi_any_v2_internal!([$($inner)*]),
60            ]
61            $($rest)*
62        )
63    };
64    ([$($elems:expr,)*] {$($inner:tt)*} , $($rest:tt)*) => {
65        $crate::pulumi_any_v2_internal_array!(
66            [
67                $($elems,)*
68                $crate::pulumi_any_v2_internal!({$($inner)*}),
69            ]
70            $($rest)*
71        )
72    };
73    ([$($elems:expr,)*] $next:expr , $($rest:tt)*) => {
74        $crate::pulumi_any_v2_internal_array!(
75            [
76                $($elems,)*
77                $crate::pulumi_any_v2_internal!($next),
78            ]
79            $($rest)*
80        )
81    };
82    ([$($elems:expr,)*] null) => {
83        $crate::pulumi_any_v2_internal_array!(
84            [
85                $($elems,)*
86                $crate::pulumi_any_v2_internal!(null),
87            ]
88        )
89    };
90    ([$($elems:expr,)*] [$($inner:tt)*]) => {
91        $crate::pulumi_any_v2_internal_array!(
92            [
93                $($elems,)*
94                $crate::pulumi_any_v2_internal!([$($inner)*]),
95            ]
96        )
97    };
98    ([$($elems:expr,)*] {$($inner:tt)*}) => {
99        $crate::pulumi_any_v2_internal_array!(
100            [
101                $($elems,)*
102                $crate::pulumi_any_v2_internal!({$($inner)*}),
103            ]
104        )
105    };
106    ([$($elems:expr,)*] $next:expr) => {
107        $crate::pulumi_any_v2_internal_array!(
108            [
109                $($elems,)*
110                $crate::pulumi_any_v2_internal!($next),
111            ]
112        )
113    };
114}
115
116#[doc(hidden)]
117#[macro_export]
118macro_rules! pulumi_any_v2_internal_object {
119    ([$($fields:expr,)*]) => {
120        $crate::__private::pulumi_gestalt_model::__private::pulumi_value_middleware_object(
121            vec![$($fields,)*]
122        )
123    };
124    ([$($fields:expr,)*] , $($rest:tt)*) => {
125        $crate::pulumi_any_v2_internal_object!([$($fields,)*] $($rest)*)
126    };
127    ([$($fields:expr,)*] $key:tt : null , $($rest:tt)*) => {
128        $crate::pulumi_any_v2_internal_object!(
129            [
130                $($fields,)*
131                (
132                    ::std::convert::Into::<::std::string::String>::into($key),
133                    $crate::pulumi_any_v2_internal!(null),
134                ),
135            ]
136            $($rest)*
137        )
138    };
139    ([$($fields:expr,)*] $key:tt : [$($inner:tt)*] , $($rest:tt)*) => {
140        $crate::pulumi_any_v2_internal_object!(
141            [
142                $($fields,)*
143                (
144                    ::std::convert::Into::<::std::string::String>::into($key),
145                    $crate::pulumi_any_v2_internal!([$($inner)*]),
146                ),
147            ]
148            $($rest)*
149        )
150    };
151    ([$($fields:expr,)*] $key:tt : {$($inner:tt)*} , $($rest:tt)*) => {
152        $crate::pulumi_any_v2_internal_object!(
153            [
154                $($fields,)*
155                (
156                    ::std::convert::Into::<::std::string::String>::into($key),
157                    $crate::pulumi_any_v2_internal!({$($inner)*}),
158                ),
159            ]
160            $($rest)*
161        )
162    };
163    ([$($fields:expr,)*] $key:tt : $value:expr , $($rest:tt)*) => {
164        $crate::pulumi_any_v2_internal_object!(
165            [
166                $($fields,)*
167                (
168                    ::std::convert::Into::<::std::string::String>::into($key),
169                    $crate::pulumi_any_v2_internal!($value),
170                ),
171            ]
172            $($rest)*
173        )
174    };
175    ([$($fields:expr,)*] $key:tt : null) => {
176        $crate::pulumi_any_v2_internal_object!(
177            [
178                $($fields,)*
179                (
180                    ::std::convert::Into::<::std::string::String>::into($key),
181                    $crate::pulumi_any_v2_internal!(null),
182                ),
183            ]
184        )
185    };
186    ([$($fields:expr,)*] $key:tt : [$($inner:tt)*]) => {
187        $crate::pulumi_any_v2_internal_object!(
188            [
189                $($fields,)*
190                (
191                    ::std::convert::Into::<::std::string::String>::into($key),
192                    $crate::pulumi_any_v2_internal!([$($inner)*]),
193                ),
194            ]
195        )
196    };
197    ([$($fields:expr,)*] $key:tt : {$($inner:tt)*}) => {
198        $crate::pulumi_any_v2_internal_object!(
199            [
200                $($fields,)*
201                (
202                    ::std::convert::Into::<::std::string::String>::into($key),
203                    $crate::pulumi_any_v2_internal!({$($inner)*}),
204                ),
205            ]
206        )
207    };
208    ([$($fields:expr,)*] $key:tt : $value:expr) => {
209        $crate::pulumi_any_v2_internal_object!(
210            [
211                $($fields,)*
212                (
213                    ::std::convert::Into::<::std::string::String>::into($key),
214                    $crate::pulumi_any_v2_internal!($value),
215                ),
216            ]
217        )
218    };
219}
220
221pub trait ToPulumiAny {
222    fn to_pulumi_any(self) -> PulumiAny;
223}
224
225impl<T> ToPulumiAny for T
226where
227    T: ToPulumiValue + Send + Sync + 'static,
228{
229    fn to_pulumi_any(self) -> PulumiAny {
230        pulumi_gestalt_model::__private::to_pulumi_value_middleware(self)
231    }
232}
233
234#[cfg(test)]
235mod tests {
236    use super::ToPulumiAny;
237    use pulumi_gestalt_model::__private::futures::executor::block_on;
238    use pulumi_gestalt_model::{
239        Output as ModelOutput, PulumiValue, PulumiValueContent, ToPulumiValue,
240    };
241    use std::collections::HashSet;
242
243    struct CustomToPulumiValue {
244        id: i32,
245    }
246
247    impl ToPulumiValue for CustomToPulumiValue {
248        fn to_pulumi_value(&self) -> impl std::future::Future<Output = PulumiValue> + Send {
249            let id = self.id;
250            std::future::ready(PulumiValue {
251                content: PulumiValueContent::Object(vec![(
252                    "custom-id".to_string(),
253                    pv(PulumiValueContent::Integer(id + 1000)),
254                )]),
255                secret: false,
256                dependencies: HashSet::new(),
257            })
258        }
259    }
260
261    fn pv(content: PulumiValueContent) -> PulumiValue {
262        PulumiValue {
263            content,
264            secret: false,
265            dependencies: HashSet::new(),
266        }
267    }
268
269    fn pvs(content: PulumiValueContent) -> PulumiValue {
270        PulumiValue {
271            content,
272            secret: true,
273            dependencies: HashSet::new(),
274        }
275    }
276
277    #[test]
278    fn to_pulumi_any_converts_plain_value() {
279        let pulumi_any = "demo".to_pulumi_any();
280        let decoded = block_on(pulumi_any.to_pulumi_value());
281        assert_eq!(decoded, pv(PulumiValueContent::String("demo".to_string())));
282    }
283
284    #[test]
285    fn pulumi_any_macro_scalar() {
286        let integer = block_on(pulumi_any!(42).to_pulumi_value());
287        assert_eq!(integer, pv(PulumiValueContent::Integer(42)));
288
289        let float = block_on(pulumi_any!(1.5f64).to_pulumi_value());
290        assert_eq!(float, pv(PulumiValueContent::Number(1.5)));
291
292        let boolean = block_on(pulumi_any!(true).to_pulumi_value());
293        assert_eq!(boolean, pv(PulumiValueContent::Boolean(true)));
294
295        let string = block_on(pulumi_any!("hello").to_pulumi_value());
296        assert_eq!(string, pv(PulumiValueContent::String("hello".to_string())));
297    }
298
299    #[test]
300    fn pulumi_any_macro_array_and_object() {
301        let array = block_on(pulumi_any!([1, 2, 3]).to_pulumi_value());
302        assert_eq!(
303            array,
304            pv(PulumiValueContent::Array(vec![
305                pv(PulumiValueContent::Integer(1)),
306                pv(PulumiValueContent::Integer(2)),
307                pv(PulumiValueContent::Integer(3)),
308            ]))
309        );
310
311        let object = block_on(pulumi_any!({"name": "macro_test", "count": 5}).to_pulumi_value());
312        assert_eq!(
313            object,
314            pv(PulumiValueContent::Object(vec![
315                ("count".to_string(), pv(PulumiValueContent::Integer(5))),
316                (
317                    "name".to_string(),
318                    pv(PulumiValueContent::String("macro_test".to_string()))
319                ),
320            ]))
321        );
322    }
323
324    #[test]
325    fn pulumi_any_macro_nested_and_trailing_commas() {
326        let value = block_on(
327            pulumi_any!({
328                "items": [
329                    1,
330                    {"name": "a",},
331                ],
332                "ok": true,
333            })
334            .to_pulumi_value(),
335        );
336
337        assert_eq!(
338            value,
339            pv(PulumiValueContent::Object(vec![
340                (
341                    "items".to_string(),
342                    pv(PulumiValueContent::Array(vec![
343                        pv(PulumiValueContent::Integer(1)),
344                        pv(PulumiValueContent::Object(vec![(
345                            "name".to_string(),
346                            pv(PulumiValueContent::String("a".to_string())),
347                        )])),
348                    ])),
349                ),
350                ("ok".to_string(), pv(PulumiValueContent::Boolean(true))),
351            ]))
352        );
353    }
354
355    #[test]
356    fn pulumi_any_macro_nested_model_outputs() {
357        let value = block_on(
358            pulumi_any!({
359                "known": ModelOutput::new(7i32),
360                "secret": ModelOutput::new_secret("sensitive"),
361                "unknown": ModelOutput::<i32>::new_nothing(),
362                "nested": [ModelOutput::new(true)],
363            })
364            .to_pulumi_value(),
365        );
366
367        assert_eq!(
368            value,
369            pvs(PulumiValueContent::Object(vec![
370                ("known".to_string(), pv(PulumiValueContent::Integer(7))),
371                (
372                    "nested".to_string(),
373                    pv(PulumiValueContent::Array(vec![pv(
374                        PulumiValueContent::Boolean(true)
375                    )])),
376                ),
377                (
378                    "secret".to_string(),
379                    pvs(PulumiValueContent::String("sensitive".to_string())),
380                ),
381                ("unknown".to_string(), pv(PulumiValueContent::Nothing)),
382            ]))
383        );
384    }
385
386    #[test]
387    fn pulumi_any_macro_object_sorts_keys() {
388        let value = block_on(
389            pulumi_any!({
390                "z": 1,
391                "a": 2,
392            })
393            .to_pulumi_value(),
394        );
395
396        assert_eq!(
397            value,
398            pv(PulumiValueContent::Object(vec![
399                ("a".to_string(), pv(PulumiValueContent::Integer(2))),
400                ("z".to_string(), pv(PulumiValueContent::Integer(1))),
401            ]))
402        );
403    }
404
405    #[test]
406    fn pulumi_any_macro_object_last_wins_for_duplicate_keys() {
407        let value = block_on(
408            pulumi_any!({
409                "a": 1,
410                "a": 2,
411                "b": 3,
412            })
413            .to_pulumi_value(),
414        );
415
416        assert_eq!(
417            value,
418            pv(PulumiValueContent::Object(vec![
419                ("a".to_string(), pv(PulumiValueContent::Integer(2))),
420                ("b".to_string(), pv(PulumiValueContent::Integer(3))),
421            ]))
422        );
423    }
424
425    #[test]
426    fn pulumi_any_macro_array_propagates_secret_from_nested_output() {
427        let value = block_on(
428            pulumi_any!([ModelOutput::new(1i32), ModelOutput::new_secret(2i32),]).to_pulumi_value(),
429        );
430
431        assert_eq!(
432            value,
433            pvs(PulumiValueContent::Array(vec![
434                pv(PulumiValueContent::Integer(1)),
435                pvs(PulumiValueContent::Integer(2)),
436            ]))
437        );
438    }
439
440    #[test]
441    fn pulumi_any_macro_uses_custom_to_pulumi_value_impl() {
442        let value = block_on(
443            pulumi_any!({
444                "custom": CustomToPulumiValue { id: 7 },
445            })
446            .to_pulumi_value(),
447        );
448
449        assert_eq!(
450            value,
451            pv(PulumiValueContent::Object(vec![(
452                "custom".to_string(),
453                pv(PulumiValueContent::Object(vec![(
454                    "custom-id".to_string(),
455                    pv(PulumiValueContent::Integer(1007)),
456                )])),
457            )]))
458        );
459    }
460}