1use std::collections::HashMap;
2
3use serde::{ser::SerializeMap, Serialize};
4
5use crate::core::{
6 logical_id::{LogicalId, LogicalIdentified},
7 parameter::Parameter,
8 resource::ManagedResource,
9};
10
11#[non_exhaustive]
12#[derive(Debug, Clone, Copy)]
13pub enum TemplateVersion {
14 V20100909,
15}
16
17impl TemplateVersion {
18 pub fn latest() -> TemplateVersion {
19 TemplateVersion::V20100909
20 }
21}
22
23impl Serialize for TemplateVersion {
24 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
25 where
26 S: serde::Serializer,
27 {
28 match self {
29 TemplateVersion::V20100909 => "2010-09-09".serialize(serializer),
30 }
31 }
32}
33
34pub struct Template {
36 format_version: TemplateVersion,
37 description: Option<String>,
38 resources: HashMap<LogicalId, Box<dyn ManagedResource>>,
39 string_parameters: Vec<Parameter<String>>,
40 number_parameters: Vec<Parameter<f64>>,
41}
42
43impl Template {
44 pub fn new() -> Self {
45 Self {
46 format_version: TemplateVersion::latest(),
47 description: None,
48 resources: HashMap::new(),
49 string_parameters: vec![],
50 number_parameters: vec![],
51 }
52 }
53
54 pub fn insert_string_param(&mut self, param: Parameter<String>) {
55 self.string_parameters.push(param);
56 }
57
58 pub fn insert_number_param(&mut self, param: Parameter<f64>) {
59 self.number_parameters.push(param);
60 }
61
62 pub fn insert_resource(
63 &mut self,
64 resource: Box<dyn ManagedResource>,
65 ) -> Option<Box<dyn ManagedResource>> {
66 self.resources
67 .insert(resource.logical_id().clone(), resource)
68 }
69}
70
71impl Serialize for Template {
72 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
73 where
74 S: serde::Serializer,
75 {
76 let mut map = serializer.serialize_map(None)?;
77 map.serialize_entry("AWSTemplateFormatVersion", &self.format_version)?;
78 if !self.string_parameters.is_empty() || !self.number_parameters.is_empty() {
79 let inner = SerParameter {
80 strings: &self.string_parameters,
81 numbers: &self.number_parameters,
82 };
83
84 map.serialize_entry("Parameters", &inner)?;
85 }
86 if let Some(description) = &self.description {
87 map.serialize_entry("Description", description)?;
88 }
89 map.serialize_entry("Resources", &self.resources)?;
90
91 map.end()
92 }
93}
94
95struct SerParameter<'a> {
96 strings: &'a [Parameter<String>],
97 numbers: &'a [Parameter<f64>],
98}
99
100impl Serialize for SerParameter<'_> {
101 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
102 where
103 S: serde::Serializer,
104 {
105 let len = self.strings.len() + self.numbers.len();
106 let mut map = serializer.serialize_map(Some(len))?;
107 for e in self.strings {
108 map.serialize_entry(e.logical_id(), e)?;
109 }
110 for e in self.numbers {
111 map.serialize_entry(e.logical_id(), e)?;
112 }
113 map.end()
114 }
115}