txtx_addon_kit/types/
types.rs

1use hcl_edit::expr::Expression;
2use hcl_edit::structure::Block;
3use indexmap::IndexMap;
4use jaq_interpret::Val;
5use serde::de::{self, MapAccess, Visitor};
6use serde::ser::SerializeMap;
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use serde_json::{Map, Value as JsonValue};
9use std::collections::VecDeque;
10use std::fmt::{self, Debug};
11
12use crate::helpers::hcl::{
13    collect_constructs_references_from_block, collect_constructs_references_from_expression,
14    visit_optional_untyped_attribute,
15};
16
17use super::diagnostics::Diagnostic;
18use super::{Did, EvaluatableInput};
19
20#[derive(Clone, Debug, Serialize)]
21#[serde(tag = "type", content = "value", rename_all = "lowercase")]
22pub enum Value {
23    Bool(bool),
24    Null,
25    #[serde(serialize_with = "i128_serializer")]
26    Integer(i128),
27    Float(f64),
28    String(String),
29    Array(Box<Vec<Value>>),
30    Object(IndexMap<String, Value>),
31    #[serde(serialize_with = "hex_serializer")]
32    Buffer(Vec<u8>),
33    #[serde(serialize_with = "addon_serializer")]
34    #[serde(untagged)]
35    Addon(AddonData),
36}
37
38impl PartialEq<Value> for Value {
39    fn eq(&self, other: &Value) -> bool {
40        match (self, other) {
41            (Value::Bool(lhs), Value::Bool(rhs)) => lhs == rhs,
42            (Value::Null, Value::Null) => true,
43            (Value::Integer(lhs), Value::Integer(rhs)) => lhs == rhs,
44            (Value::Float(lhs), Value::Float(rhs)) => lhs == rhs,
45            (Value::String(lhs), Value::String(rhs)) => lhs == rhs,
46            (Value::Buffer(lhs), Value::Buffer(rhs)) => lhs == rhs,
47            (Value::Object(lhs), Value::Object(rhs)) => {
48                if lhs.len() != rhs.len() {
49                    return false;
50                }
51                for (k, v) in lhs.iter() {
52                    if let Some(r) = rhs.get(k) {
53                        if v != r {
54                            return false;
55                        }
56                    } else {
57                        return false;
58                    }
59                }
60                true
61            }
62            (Value::Array(lhs), Value::Array(rhs)) => {
63                if lhs.len() != rhs.len() {
64                    return false;
65                }
66                for (l, r) in lhs.iter().zip(rhs.iter()) {
67                    if l != r {
68                        return false;
69                    }
70                }
71                true
72            }
73            (Value::Addon(lhs), Value::Addon(rhs)) => {
74                if lhs.id != rhs.id {
75                    return false;
76                }
77                lhs.bytes == rhs.bytes
78            }
79            _ => false,
80        }
81    }
82}
83
84fn i128_serializer<S>(value: &i128, ser: S) -> Result<S::Ok, S::Error>
85where
86    S: Serializer,
87{
88    ser.serialize_str(&value.to_string())
89}
90
91fn hex_serializer<S>(bytes: &Vec<u8>, ser: S) -> Result<S::Ok, S::Error>
92where
93    S: Serializer,
94{
95    let value = format!("0x{}", hex::encode(&bytes));
96    ser.serialize_str(&value)
97}
98
99fn addon_serializer<S>(addon_data: &AddonData, ser: S) -> Result<S::Ok, S::Error>
100where
101    S: Serializer,
102{
103    let mut map = ser.serialize_map(Some(2))?;
104    map.serialize_entry("type", &addon_data.id)?;
105    let value = format!("0x{}", hex::encode(&addon_data.bytes));
106    map.serialize_entry("value", &value)?;
107    map.end()
108}
109
110impl<'de> Deserialize<'de> for Value {
111    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
112    where
113        D: Deserializer<'de>,
114    {
115        struct ValueVisitor;
116
117        fn decode_hex_string(value: String) -> Result<Vec<u8>, String> {
118            let value = value.replace("0x", "");
119            hex::decode(&value)
120                .map_err(|e| format!("failed to decode hex string ({}) to bytes: {}", value, e))
121        }
122        impl<'de> Visitor<'de> for ValueVisitor {
123            type Value = Value;
124
125            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
126                formatter.write_str("a valid Value")
127            }
128
129            fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
130            where
131                M: MapAccess<'de>,
132            {
133                let mut typing = None;
134                while let Some(key) = map.next_key::<String>()? {
135                    match key.as_str() {
136                        "type" => {
137                            if typing.is_some() {
138                                return Err(de::Error::duplicate_field("type"));
139                            }
140                            let the_typing = map.next_value::<String>()?;
141                            if the_typing.eq("null") {
142                                return Ok(Value::null());
143                            }
144                            typing = Some(the_typing);
145                        }
146                        "value" => {
147                            if typing.is_none() {
148                                let Some(key) = map.next_key::<String>()? else {
149                                    return Err(de::Error::missing_field("type"));
150                                };
151                                match key.as_str() {
152                                    "type" => {
153                                        let the_typing = map.next_value::<String>()?;
154                                        if the_typing.eq("null") {
155                                            return Ok(Value::null());
156                                        }
157                                        typing = Some(the_typing);
158                                    }
159                                    unexpected => {
160                                        return Err(de::Error::custom(format!(
161                                            "invalid Value: unexpected key {unexpected}"
162                                        )))
163                                    }
164                                };
165                            }
166                            let typing = typing.ok_or_else(|| de::Error::missing_field("type"))?;
167                            match typing.as_str() {
168                                "bool" => return Ok(Value::bool(map.next_value()?)),
169                                "integer" => {
170                                    let value: String = map.next_value()?;
171                                    let i128 = value.parse().map_err(serde::de::Error::custom)?;
172                                    return Ok(Value::integer(i128));
173                                }
174                                "float" => return Ok(Value::float(map.next_value()?)),
175                                "string" => return Ok(Value::string(map.next_value()?)),
176                                "null" => unreachable!(),
177                                "buffer" => {
178                                    let bytes =
179                                        decode_hex_string(map.next_value()?).map_err(|e| {
180                                            de::Error::custom(format!(
181                                                "failed to deserialize buffer: {e}"
182                                            ))
183                                        })?;
184                                    return Ok(Value::buffer(bytes));
185                                }
186                                "object" => return Ok(Value::object(map.next_value()?)),
187
188                                "array" => return Ok(Value::array(map.next_value()?)),
189                                other => {
190                                    if other.contains("::") {
191                                        let bytes =
192                                            decode_hex_string(map.next_value()?).map_err(|e| {
193                                                de::Error::custom(format!(
194                                                    "failed to deserialize buffer: {e}"
195                                                ))
196                                            })?;
197                                        return Ok(Value::addon(bytes, other));
198                                    } else {
199                                        return Err(de::Error::custom(format!(
200                                            "invalid type {other}"
201                                        )));
202                                    }
203                                }
204                            }
205                        }
206                        unexpected => {
207                            return Err(de::Error::custom(format!(
208                                "invalid Value: unexpected key {unexpected}"
209                            )));
210                        }
211                    }
212                }
213
214                Err(de::Error::custom("invalid Value: missing required key value"))
215            }
216        }
217
218        deserializer.deserialize_any(ValueVisitor)
219    }
220}
221
222impl Value {
223    pub fn string(value: String) -> Value {
224        Value::String(value.to_string())
225    }
226    pub fn integer(value: i128) -> Value {
227        Value::Integer(value)
228    }
229    pub fn float(value: f64) -> Value {
230        Value::Float(value)
231    }
232    pub fn null() -> Value {
233        Value::Null
234    }
235    pub fn bool(value: bool) -> Value {
236        Value::Bool(value)
237    }
238    pub fn buffer(bytes: Vec<u8>) -> Value {
239        Value::Buffer(bytes)
240    }
241    pub fn array(array: Vec<Value>) -> Value {
242        Value::Array(Box::new(array))
243    }
244    pub fn object(object: IndexMap<String, Value>) -> Value {
245        Value::Object(object)
246    }
247
248    pub fn addon(bytes: Vec<u8>, id: &str) -> Value {
249        Value::Addon(AddonData { bytes, id: id.to_string() })
250    }
251
252    pub fn expect_string(&self) -> &str {
253        match &self {
254            Value::String(value) => value,
255            _ => unreachable!(),
256        }
257    }
258    pub fn expect_integer(&self) -> i128 {
259        match &self {
260            Value::Integer(value) => *value,
261            _ => unreachable!(),
262        }
263    }
264    pub fn expect_uint(&self) -> Result<u64, String> {
265        match &self {
266            Value::Integer(value) => i128_to_u64(*value),
267            _ => unreachable!(),
268        }
269    }
270    pub fn expect_float(&self) -> f64 {
271        match &self {
272            Value::Float(value) => *value,
273            _ => unreachable!(),
274        }
275    }
276    pub fn expect_null(&self) -> () {
277        match &self {
278            Value::Null => (),
279            _ => unreachable!(),
280        }
281    }
282    pub fn expect_bool(&self) -> bool {
283        match &self {
284            Value::Bool(value) => *value,
285            _ => unreachable!(),
286        }
287    }
288    pub fn expect_buffer_data(&self) -> &Vec<u8> {
289        match &self {
290            Value::Buffer(value) => &value,
291            _ => unreachable!(),
292        }
293    }
294    pub fn expect_addon_data(&self) -> &AddonData {
295        match &self {
296            Value::Addon(value) => &value,
297            _ => unreachable!(),
298        }
299    }
300
301    #[deprecated(note = "use `get_buffer_bytes_result` instead")]
302    pub fn expect_buffer_bytes(&self) -> Vec<u8> {
303        self.try_get_buffer_bytes_result().unwrap().expect("unable to retrieve bytes")
304    }
305
306    pub fn get_buffer_bytes_result(&self) -> Result<Vec<u8>, String> {
307        self.try_get_buffer_bytes_result()?.ok_or("unable to retrieve bytes".into())
308    }
309
310    #[deprecated(note = "use `try_get_buffer_bytes_result` instead")]
311    pub fn try_get_buffer_bytes(&self) -> Option<Vec<u8>> {
312        let bytes = match &self {
313            Value::Buffer(value) => value.clone(),
314            Value::String(bytes) => {
315                let bytes = if bytes.starts_with("0x") {
316                    crate::hex::decode(&bytes[2..]).unwrap()
317                } else {
318                    crate::hex::decode(&bytes).unwrap()
319                };
320                bytes
321            }
322            Value::Array(values) => {
323                values.iter().flat_map(|v| v.get_buffer_bytes_result().unwrap()).collect()
324            }
325            Value::Addon(addon_value) => addon_value.bytes.clone(),
326            _ => return None,
327        };
328
329        Some(bytes)
330    }
331
332    pub fn try_get_buffer_bytes_result(&self) -> Result<Option<Vec<u8>>, String> {
333        let bytes = match &self {
334            Value::Buffer(value) => value.clone(),
335            Value::String(bytes) => {
336                let stripped = if bytes.starts_with("0x") { &bytes[2..] } else { &bytes[..] };
337                let bytes = crate::hex::decode(stripped).map_err(|e| {
338                    format!("string '{}' could not be decoded to hex bytes: {}", bytes, e)
339                })?;
340                bytes
341            }
342            Value::Array(values) => values
343                .iter()
344                .map(|v| v.try_get_buffer_bytes_result())
345                .collect::<Result<Vec<Option<_>>, String>>()?
346                .into_iter()
347                .filter_map(|v| v)
348                .flat_map(|v| v)
349                .collect(),
350            Value::Addon(addon_value) => addon_value.bytes.clone(),
351            _ => return Ok(None),
352        };
353
354        Ok(Some(bytes))
355    }
356    pub fn expect_array(&self) -> &Box<Vec<Value>> {
357        match &self {
358            Value::Array(value) => value,
359            _ => unreachable!(),
360        }
361    }
362
363    pub fn expect_object(&self) -> &IndexMap<String, Value> {
364        match &self {
365            Value::Object(value) => value,
366            _ => unreachable!(),
367        }
368    }
369
370    pub fn as_string(&self) -> Option<&str> {
371        match &self {
372            Value::String(value) => Some(value),
373            _ => None,
374        }
375    }
376    pub fn as_integer(&self) -> Option<i128> {
377        match &self {
378            Value::Integer(value) => Some(*value),
379            _ => None,
380        }
381    }
382    pub fn as_uint(&self) -> Option<Result<u64, String>> {
383        match &self {
384            Value::Integer(value) => Some(i128_to_u64(*value)),
385            _ => None,
386        }
387    }
388    pub fn as_u8(&self) -> Option<Result<u8, String>> {
389        match &self {
390            Value::Integer(value) => {
391                Some(u8::try_from(*value).map_err(|e| format!("invalid u8: {e}")))
392            }
393            _ => None,
394        }
395    }
396    pub fn as_u16(&self) -> Option<Result<u16, String>> {
397        match &self {
398            Value::Integer(value) => {
399                Some(u16::try_from(*value).map_err(|e| format!("invalid u16: {e}")))
400            }
401            _ => None,
402        }
403    }
404    pub fn as_float(&self) -> Option<f64> {
405        match &self {
406            Value::Float(value) => Some(*value),
407            _ => None,
408        }
409    }
410    pub fn as_null(&self) -> Option<()> {
411        match &self {
412            Value::Null => Some(()),
413            _ => None,
414        }
415    }
416    pub fn as_bool(&self) -> Option<bool> {
417        match &self {
418            Value::Bool(value) => Some(*value),
419            _ => None,
420        }
421    }
422    pub fn as_buffer_data(&self) -> Option<&Vec<u8>> {
423        match &self {
424            Value::Buffer(value) => Some(&value),
425            _ => None,
426        }
427    }
428    pub fn as_addon_data(&self) -> Option<&AddonData> {
429        match &self {
430            Value::Addon(value) => Some(&value),
431            _ => None,
432        }
433    }
434    pub fn as_array(&self) -> Option<&Box<Vec<Value>>> {
435        match &self {
436            Value::Array(value) => Some(value),
437            _ => None,
438        }
439    }
440
441    pub fn as_map(&self) -> Option<&Box<Vec<Value>>> {
442        match &self {
443            Value::Array(value) => Some(value),
444            _ => None,
445        }
446    }
447
448    pub fn as_object(&self) -> Option<&IndexMap<String, Value>> {
449        match &self {
450            Value::Object(value) => Some(value),
451            _ => None,
452        }
453    }
454
455    pub fn as_object_mut(&mut self) -> Option<&mut IndexMap<String, Value>> {
456        match self {
457            Value::Object(value) => Some(value),
458            _ => None,
459        }
460    }
461
462    pub fn get_keys_from_object(&self, mut keys: VecDeque<String>) -> Result<Value, Diagnostic> {
463        let Some(key) = keys.pop_front() else {
464            return Ok(self.clone());
465        };
466
467        if let Some(ref object) = self.as_object() {
468            match object.get(&key) {
469                Some(val) => val.get_keys_from_object(keys),
470                None => {
471                    Err(Diagnostic::error_from_string(format!("missing key '{}' from object", key)))
472                }
473            }
474        } else {
475            Err(Diagnostic::error_from_string(format!("invalid key '{}' for object", key)))
476        }
477    }
478
479    pub fn is_type_eq(&self, rhs: &Value) -> bool {
480        match (self, rhs) {
481            (Value::Null, Value::Null) => true,
482            (Value::Bool(_), Value::Bool(_)) => true,
483            (Value::Integer(_), Value::Integer(_)) => true,
484            (Value::Float(_), Value::Float(_)) => true,
485            (Value::String(_), Value::String(_)) => true,
486            (Value::Buffer(_), Value::Buffer(_)) => true,
487            (Value::Object(_), Value::Object(_)) => true,
488            (Value::Null, _) => false,
489            (Value::Bool(_), _) => false,
490            (Value::Integer(_), _) => false,
491            (Value::Float(_), _) => false,
492            (Value::String(_), _) => false,
493            (Value::Buffer(_), _) => false,
494            (Value::Object(_), _) => false,
495            (Value::Array(lhs), Value::Array(rhs)) => {
496                let Some(first_lhs) = lhs.first() else {
497                    return false;
498                };
499                let Some(first_rhs) = rhs.first() else {
500                    return false;
501                };
502                first_lhs.is_type_eq(first_rhs)
503            }
504            (Value::Array(_), _) => false,
505            (Value::Addon(lhs), Value::Addon(rhs)) => lhs.id == rhs.id,
506            (Value::Addon(_), _) => false,
507        }
508    }
509    pub fn to_bytes(&self) -> Vec<u8> {
510        match &self {
511            Value::Buffer(bytes) => bytes.clone(),
512            Value::Array(values) => {
513                let mut joined = vec![];
514                for value in values.iter() {
515                    joined.extend(value.to_bytes());
516                }
517                joined
518            }
519            Value::String(bytes) => {
520                let bytes = if bytes.starts_with("0x") {
521                    crate::hex::decode(&bytes[2..]).unwrap()
522                } else {
523                    match crate::hex::decode(&bytes) {
524                        Ok(res) => res,
525                        Err(_) => bytes.as_bytes().to_vec(),
526                    }
527                };
528                bytes
529            }
530            Value::Addon(data) => data.bytes.clone(),
531            Value::Integer(value) => value.to_be_bytes().to_vec(),
532            Value::Float(value) => value.to_be_bytes().to_vec(),
533            Value::Bool(value) => vec![*value as u8],
534            Value::Null => vec![],
535            Value::Object(values) => {
536                let mut joined = vec![];
537                for (key, value) in values.iter() {
538                    joined.extend(key.as_bytes());
539                    joined.extend(value.to_bytes());
540                }
541                joined
542            }
543        }
544    }
545
546    pub fn parse_and_default_to_string(value_str: &str) -> Value {
547        let trim = value_str.trim();
548        let value = match trim.parse::<i128>() {
549            Ok(uint) => Value::integer(uint),
550            Err(_) => {
551                if trim.starts_with("[") || trim.starts_with("(") {
552                    let values_to_parse = trim[1..trim.len() - 1].split(",").collect::<Vec<_>>();
553                    let mut values = vec![];
554                    for v in values_to_parse.iter() {
555                        values.push(Value::parse_and_default_to_string(v));
556                    }
557                    Value::array(values)
558                } else {
559                    Value::string(trim.into())
560                }
561            }
562        };
563        value
564    }
565
566    pub fn compute_fingerprint(&self) -> Did {
567        let bytes = self.to_bytes();
568        Did::from_components(vec![bytes])
569    }
570
571    pub fn to_json(&self) -> JsonValue {
572        let json = match self {
573            Value::Bool(b) => JsonValue::Bool(*b),
574            Value::Null => JsonValue::Null,
575            Value::Integer(i) => JsonValue::Number(serde_json::Number::from(*i as i64)),
576            Value::Float(f) => JsonValue::Number(serde_json::Number::from_f64(*f).unwrap()),
577            Value::String(s) => JsonValue::String(s.to_string()),
578            Value::Array(vec) => {
579                JsonValue::Array(vec.iter().map(|v| v.to_json()).collect::<Vec<JsonValue>>())
580            }
581            Value::Object(index_map) => JsonValue::Object(
582                index_map
583                    .iter()
584                    .map(|(k, v)| (k.clone(), v.to_json()))
585                    .collect::<Map<String, JsonValue>>(),
586            ),
587            Value::Buffer(vec) => JsonValue::String(format!("0x{}", hex::encode(&vec))),
588            Value::Addon(addon_data) => JsonValue::String(addon_data.to_string()),
589        };
590        json
591    }
592}
593
594fn i128_to_u64(i128: i128) -> Result<u64, String> {
595    u64::try_from(i128).map_err(|e| format!("invalid uint: {e}"))
596}
597impl Value {
598    pub fn to_string(&self) -> String {
599        match self {
600            Value::String(val) => val.clone(),
601            Value::Bool(val) => val.to_string(),
602            Value::Integer(val) => val.to_string(),
603            Value::Float(val) => val.to_string(),
604            Value::Null => "null".to_string(),
605            Value::Buffer(bytes) => {
606                format!("0x{}", hex::encode(&bytes))
607            }
608            Value::Object(obj) => {
609                let mut res = "{".to_string();
610                let len = obj.len();
611                for (i, (k, v)) in obj.iter().enumerate() {
612                    res.push_str(&format!(
613                        r#""{}": {}{}"#,
614                        k,
615                        v.to_string(),
616                        if i == (len - 1) { "" } else { "," }
617                    ));
618                }
619                res
620            }
621            Value::Array(array) => {
622                format!("[{}]", array.iter().map(|e| e.to_string()).collect::<Vec<_>>().join(", "))
623            }
624            Value::Addon(addon_value) => addon_value.to_string(),
625        }
626    }
627
628    /// The same as [Value::to_string], but strings are wrapped in double quotes.
629    /// This is useful for generating JSON-formatted strings.
630    /// I don't know if there are side effects to the [Value::to_string] method having
631    /// the double quoted strings, so I'm keeping this separate for now.
632    pub fn encode_to_string(&self) -> String {
633        match self {
634            Value::String(val) => format!(r#""{val}""#),
635            Value::Bool(val) => val.to_string(),
636            Value::Integer(val) => val.to_string(),
637            Value::Float(val) => val.to_string(),
638            Value::Null => "null".to_string(),
639            Value::Buffer(bytes) => {
640                format!(r#""0x{}""#, hex::encode(&bytes))
641            }
642            Value::Object(obj) => {
643                let mut res = "{".to_string();
644                let len = obj.len();
645                for (i, (k, v)) in obj.iter().enumerate() {
646                    res.push_str(&format!(
647                        r#"
648    "{}": {}{}"#,
649                        k,
650                        v.encode_to_string(),
651                        if i == (len - 1) { "" } else { "," }
652                    ));
653                }
654                res.push_str(&format!(
655                    r#"
656}}"#
657                ));
658                res
659            }
660            Value::Array(array) => {
661                format!(
662                    "[{}]",
663                    array.iter().map(|e| e.encode_to_string()).collect::<Vec<_>>().join(", ")
664                )
665            }
666            Value::Addon(addon_value) => addon_value.encode_to_string(),
667        }
668    }
669
670    pub fn from_jaq_value(value: &Val) -> Result<Value, String> {
671        let res = match value {
672            Val::Null => Value::null(),
673            Val::Bool(val) => Value::bool(*val),
674            Val::Num(val) => val
675                .parse::<i128>()
676                .map(Value::integer)
677                .map_err(|e| format!("Failed to parse number: {}", e))?,
678            Val::Int(val) => i128::try_from(*val)
679                .map(Value::integer)
680                .map_err(|e| format!("Failed to convert integer: {}", e))?,
681            Val::Float(val) => Value::float(*val),
682            Val::Str(val) => Value::string(val.to_string()),
683            Val::Arr(val) => Value::array(
684                val.iter()
685                    .map(|v| Value::from_jaq_value(v))
686                    .collect::<Result<Vec<Value>, String>>()?,
687            ),
688            Val::Obj(val) => ObjectType::from(
689                val.iter()
690                    .map(|(k, v)| Value::from_jaq_value(v).map(|v| (k.as_str(), v)))
691                    .collect::<Result<Vec<(&str, Value)>, String>>()?,
692            )
693            .to_value(),
694        };
695        Ok(res)
696    }
697    pub fn get_type(&self) -> Type {
698        match self {
699            Value::Bool(_) => Type::Bool,
700            Value::Null => Type::Null,
701            Value::Integer(_) => Type::Integer,
702            Value::Float(_) => Type::Float,
703            Value::String(_) => Type::String,
704            Value::Buffer(_) => Type::Buffer,
705            Value::Object(_) => Type::Object(ObjectDefinition::arbitrary()),
706            Value::Array(t) => {
707                Type::Array(Box::new(t.first().unwrap_or(&Value::null()).get_type()))
708            }
709            Value::Addon(t) => Type::Addon(t.id.clone()),
710        }
711    }
712}
713
714// impl Serialize for PrimitiveValue {
715//     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
716//     where
717//         S: Serializer,
718//     {
719//         match self {
720//             PrimitiveValue::String(val) => serializer.serialize_str(val),
721//             PrimitiveValue::UnsignedInteger(val) => serializer.serialize_u64(*val),
722//             PrimitiveValue::SignedInteger(val) => serializer.serialize_i64(*val),
723//             PrimitiveValue::Float(val) => serializer.serialize_f64(*val),
724//             PrimitiveValue::Bool(val) => serializer.serialize_bool(*val),
725//             PrimitiveValue::Null => serializer.serialize_none(),
726//             PrimitiveValue::Buffer(BufferData { bytes, typing: _ }) => {
727//                 let mut s = String::from("0x");
728//                 s.write_str(
729//                     &bytes
730//                         .iter()
731//                         .map(|b| format!("{:02X}", b))
732//                         .collect::<String>(),
733//                 )
734//                 .unwrap();
735//                 serializer.serialize_str(&s)
736//             }
737//         }
738//     }
739// }
740
741#[derive(Clone, Debug)]
742pub struct ObjectType {
743    map: IndexMap<String, Value>,
744}
745impl ObjectType {
746    pub fn new() -> Self {
747        ObjectType { map: IndexMap::new() }
748    }
749
750    pub fn from_map(map: IndexMap<String, Value>) -> Self {
751        ObjectType { map }
752    }
753
754    pub fn from<S: ToString, T: IntoIterator<Item = (S, Value)>>(default: T) -> Self {
755        let mut map = IndexMap::new();
756        for (key, value) in default {
757            map.insert(key.to_string(), value);
758        }
759        ObjectType { map }
760    }
761
762    pub fn insert(&mut self, key: &str, value: Value) -> &mut Self {
763        self.map.insert(key.to_string(), value);
764        self
765    }
766
767    pub fn inner(&self) -> IndexMap<String, Value> {
768        self.map.clone()
769    }
770    pub fn to_value(&self) -> Value {
771        Value::object(self.map.clone())
772    }
773}
774
775#[derive(Clone, Serialize, Deserialize, PartialEq)]
776pub struct AddonData {
777    pub bytes: Vec<u8>,
778    pub id: String,
779}
780impl AddonData {
781    pub fn to_string(&self) -> String {
782        format!("0x{}", hex::encode(&self.bytes))
783    }
784    pub fn encode_to_string(&self) -> String {
785        format!(r#""0x{}""#, hex::encode(&self.bytes))
786    }
787}
788
789impl fmt::Debug for AddonData {
790    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
791        // You can customize the output format here.
792        f.debug_struct("AddonData").field("bytes", &self.to_string()).field("id", &self.id).finish()
793    }
794}
795
796#[derive(Clone, Debug, Eq, PartialEq, Hash)]
797pub enum Type {
798    Bool,
799    Null,
800    Integer,
801    Float,
802    String,
803    Buffer,
804    Object(ObjectDefinition),
805    Addon(String),
806    Array(Box<Type>),
807    Map(ObjectDefinition),
808}
809
810impl Type {
811    pub fn string() -> Type {
812        Type::String
813    }
814    pub fn integer() -> Type {
815        Type::Integer
816    }
817    pub fn float() -> Type {
818        Type::Float
819    }
820    pub fn null() -> Type {
821        Type::Null
822    }
823    pub fn bool() -> Type {
824        Type::Bool
825    }
826    pub fn object(def: ObjectDefinition) -> Type {
827        Type::Object(def)
828    }
829    pub fn strict_object(props: Vec<ObjectProperty>) -> Type {
830        Type::Object(ObjectDefinition::strict(props))
831    }
832    pub fn arbitrary_object() -> Type {
833        Type::Object(ObjectDefinition::arbitrary())
834    }
835    pub fn documented_arbitrary_object(props: Vec<ObjectProperty>) -> Type {
836        Type::Object(ObjectDefinition::documented_arbitrary(props))
837    }
838    pub fn map(def: ObjectDefinition) -> Type {
839        Type::Map(def)
840    }
841    pub fn strict_map(props: Vec<ObjectProperty>) -> Type {
842        Type::Map(ObjectDefinition::strict(props))
843    }
844    pub fn arbitrary_map() -> Type {
845        Type::Map(ObjectDefinition::arbitrary())
846    }
847    pub fn documented_arbitrary_map(props: Vec<ObjectProperty>) -> Type {
848        Type::Map(ObjectDefinition::documented_arbitrary(props))
849    }
850    pub fn buffer() -> Type {
851        Type::Buffer
852    }
853    pub fn addon(id: &str) -> Type {
854        Type::Addon(id.to_string())
855    }
856    pub fn array(array_item_type: Type) -> Type {
857        Type::Array(Box::new(array_item_type))
858    }
859
860    pub fn check_value(&self, value: &Value) -> Result<(), Diagnostic> {
861        let mismatch_err = |expected: &str| {
862            Diagnostic::error_from_string(format!(
863                "expected {}, got {}",
864                expected,
865                value.get_type().to_string()
866            ))
867        };
868
869        match &self {
870            Type::Bool => value.as_bool().map(|_| ()).ok_or_else(|| mismatch_err("bool"))?,
871            Type::Null => value.as_null().map(|_| ()).ok_or_else(|| mismatch_err("null"))?,
872            Type::Integer => {
873                value.as_integer().map(|_| ()).ok_or_else(|| mismatch_err("integer"))?
874            }
875            Type::Float => value.as_float().map(|_| ()).ok_or_else(|| mismatch_err("float"))?,
876            Type::String => value.as_string().map(|_| ()).ok_or_else(|| mismatch_err("string"))?,
877            Type::Buffer => {
878                value.as_buffer_data().map(|_| ()).ok_or_else(|| mismatch_err("buffer"))?
879            }
880            Type::Addon(addon_type) => value
881                .as_addon_data()
882                .map(|_| ())
883                .ok_or_else(|| mismatch_err(&format!("addon type '{}'", addon_type)))?,
884            Type::Array(array_type) => value
885                .as_array()
886                .map(|_| ())
887                .ok_or_else(|| mismatch_err(&format!("array<{}>", array_type.to_string())))?,
888            Type::Object(object_def) | Type::Map(object_def) => match object_def {
889                ObjectDefinition::Strict(props) => {
890                    let object = value.as_object().ok_or_else(|| mismatch_err("object"))?;
891                    for expected_prop in props.iter() {
892                        let prop_value = object.get(&expected_prop.name);
893                        if expected_prop.optional && prop_value.is_none() {
894                            continue;
895                        }
896                        let prop_value = prop_value.ok_or_else(|| {
897                            Diagnostic::error_from_string(format!(
898                                "missing required property '{}'",
899                                expected_prop.name,
900                            ))
901                        })?;
902                        expected_prop.typing.check_value(prop_value).map_err(|e| {
903                            Diagnostic::error_from_string(format!(
904                                "object property '{}': {}",
905                                expected_prop.name, e.message
906                            ))
907                        })?;
908                    }
909                }
910                ObjectDefinition::Arbitrary(_) => {
911                    let _ = value.as_object().ok_or_else(|| mismatch_err("object"))?;
912                }
913            }, //  => todo!(),
914        };
915        Ok(())
916    }
917
918    pub fn as_object(&self) -> Option<&ObjectDefinition> {
919        match self {
920            Type::Object(props) => Some(props),
921            _ => None,
922        }
923    }
924
925    pub fn as_array(&self) -> Option<&Box<Type>> {
926        match self {
927            Type::Array(typing) => Some(typing),
928            _ => None,
929        }
930    }
931
932    pub fn as_map(&self) -> Option<&ObjectDefinition> {
933        match self {
934            Type::Map(props) => Some(props),
935            _ => None,
936        }
937    }
938
939    pub fn as_action(&self) -> Option<&String> {
940        match self {
941            Type::Addon(action) => Some(action),
942            _ => None,
943        }
944    }
945
946    /// This function will get attributes from the provided HCL block that match the input name.
947    /// It will collect all expressions in the block that reference other constructs, according
948    /// to the rules defined by the `Type`.
949    ///
950    /// For example, while most types will just get the attribute value, the `Object` and `Map` types
951    /// need to look for nested blocks and properties.
952    pub fn get_expressions_referencing_constructs<'a>(
953        &self,
954        block: &Block,
955        input: Box<dyn EvaluatableInput>,
956        dependencies: &mut Vec<(Option<Box<dyn EvaluatableInput>>, Expression)>,
957    ) {
958        let input_name = input.name();
959        match self {
960            Type::Map(ref object_def) => match object_def {
961                ObjectDefinition::Strict(props) => {
962                    for block in block.body.get_blocks(&input_name) {
963                        for prop in props.iter() {
964                            let res = visit_optional_untyped_attribute(&prop.name, &block);
965                            if let Some(expr) = res {
966                                collect_constructs_references_from_expression(
967                                    &expr,
968                                    Some(input.clone()),
969                                    dependencies,
970                                );
971                            }
972                        }
973                    }
974                }
975                ObjectDefinition::Arbitrary(_) => {
976                    for block in block.body.get_blocks(&input_name) {
977                        collect_constructs_references_from_block(
978                            block,
979                            Some(input.clone()),
980                            dependencies,
981                        );
982                    }
983                }
984            },
985            Type::Object(ref object_def) => {
986                if let Some(expr) = visit_optional_untyped_attribute(&input_name, &block) {
987                    collect_constructs_references_from_expression(
988                        &expr,
989                        Some(input.clone()),
990                        dependencies,
991                    );
992                }
993                match object_def {
994                    ObjectDefinition::Strict(props) => {
995                        for prop in props.iter() {
996                            for block in block.body.get_blocks(&input_name) {
997                                if let Some(expr) =
998                                    visit_optional_untyped_attribute(&prop.name, &block)
999                                {
1000                                    collect_constructs_references_from_expression(
1001                                        &expr,
1002                                        Some(input.clone()),
1003                                        dependencies,
1004                                    );
1005                                }
1006                            }
1007                        }
1008                    }
1009                    ObjectDefinition::Arbitrary(_) => {
1010                        for block in block.body.get_blocks(&input_name) {
1011                            collect_constructs_references_from_block(
1012                                block,
1013                                Some(input.clone()),
1014                                dependencies,
1015                            );
1016                        }
1017                    }
1018                }
1019            }
1020            _ => {
1021                if let Some(expr) = visit_optional_untyped_attribute(&input_name, &block) {
1022                    collect_constructs_references_from_expression(&expr, Some(input), dependencies);
1023                }
1024            }
1025        }
1026    }
1027}
1028
1029impl Type {
1030    pub fn to_string(&self) -> String {
1031        match self {
1032            Type::Bool => "bool".into(),
1033            Type::Null => "null".into(),
1034            Type::Integer => "integer".into(),
1035            Type::Float => "float".into(),
1036            Type::String => "string".into(),
1037            Type::Buffer => "buffer".into(),
1038            Type::Object(_) => "object".into(),
1039            Type::Addon(addon) => format!("addon({})", addon),
1040            Type::Array(typing) => format!("array[{}]", typing.to_string()),
1041            Type::Map(_) => "map".into(),
1042        }
1043    }
1044}
1045
1046impl Default for Type {
1047    fn default() -> Self {
1048        Type::string()
1049    }
1050}
1051impl TryFrom<String> for Type {
1052    type Error = String;
1053    fn try_from(value: String) -> Result<Self, Self::Error> {
1054        let val = match value.as_str() {
1055            "string" => Type::String,
1056            "integer" => Type::Integer,
1057            "float" => Type::Float,
1058            "bool" => Type::Bool,
1059            "null" => Type::Null,
1060            "buffer" => Type::Buffer,
1061            "object" => Type::Object(ObjectDefinition::arbitrary()),
1062            other => {
1063                if other.starts_with("array[") && other.ends_with("]") {
1064                    let mut inner = other.replace("array[", "");
1065                    inner = inner.replace("]", "");
1066                    return Type::try_from(inner);
1067                } else if other.starts_with("addon(") {
1068                    let mut inner = other.replace("addon(", "");
1069                    inner = inner.replace(")", "");
1070                    Type::addon(&inner)
1071                } else {
1072                    return Err(format!("invalid type: {}", other));
1073                }
1074            }
1075        };
1076        Ok(val)
1077    }
1078}
1079
1080impl Serialize for Type {
1081    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1082    where
1083        S: Serializer,
1084    {
1085        serializer.serialize_str(&self.to_string())
1086    }
1087}
1088
1089impl<'de> Deserialize<'de> for Type {
1090    fn deserialize<D>(deserializer: D) -> Result<Type, D::Error>
1091    where
1092        D: Deserializer<'de>,
1093    {
1094        let type_str: String = serde::Deserialize::deserialize(deserializer)?;
1095        let t = Type::try_from(type_str).map_err(serde::de::Error::custom)?;
1096        Ok(t)
1097    }
1098}
1099
1100#[derive(Clone, Debug, Eq, PartialEq, Hash)]
1101pub enum ObjectDefinition {
1102    /// Strict object definition with a list of properties
1103    Strict(Vec<ObjectProperty>),
1104    /// Arbitrary object definition with no specific properties
1105    /// The optional list of object properties is used for documenting
1106    /// Some of the potential properties.
1107    Arbitrary(Option<Vec<ObjectProperty>>),
1108}
1109
1110impl ObjectDefinition {
1111    pub fn strict(props: Vec<ObjectProperty>) -> Self {
1112        ObjectDefinition::Strict(props)
1113    }
1114
1115    pub fn arbitrary() -> Self {
1116        ObjectDefinition::Arbitrary(None)
1117    }
1118
1119    pub fn documented_arbitrary(props: Vec<ObjectProperty>) -> Self {
1120        ObjectDefinition::Arbitrary(Some(props))
1121    }
1122
1123    pub fn join_documentation(&self, recursion_depth: usize) -> String {
1124        match self {
1125            ObjectDefinition::Strict(props) | ObjectDefinition::Arbitrary(Some(props)) => props
1126                .iter()
1127                .map(|prop| {
1128                    format!(
1129                        "{}- **{}**: {}",
1130                        " ".repeat((recursion_depth + 1) * 2),
1131                        prop.name,
1132                        prop.join_documentation(recursion_depth + 1)
1133                    )
1134                })
1135                .collect::<Vec<String>>()
1136                .join("\n"),
1137            ObjectDefinition::Arbitrary(None) => String::new(),
1138        }
1139    }
1140}
1141
1142#[derive(Clone, Debug, Eq, PartialEq, Hash)]
1143pub struct ObjectProperty {
1144    pub name: String,
1145    pub documentation: String,
1146    pub typing: Type,
1147    pub optional: bool,
1148    pub tainting: bool,
1149    pub internal: bool,
1150}
1151
1152impl ObjectProperty {
1153    pub fn join_documentation(&self, recursion_depth: usize) -> String {
1154        match &self.typing {
1155            Type::Object(object_definition) => {
1156                format!(
1157                    "{} This is an object type containing the keys:\n{}",
1158                    self.documentation,
1159                    object_definition.join_documentation(recursion_depth)
1160                )
1161            }
1162            Type::Map(object_definition) => {
1163                format!(
1164                    "{} This is a map type containing the keys:\n{}",
1165                    self.documentation,
1166                    object_definition.join_documentation(recursion_depth)
1167                )
1168            }
1169            _ => self.documentation.clone(),
1170        }
1171    }
1172}
1173
1174#[derive(Clone, Debug)]
1175pub struct RunbookSupervisionContext {
1176    pub review_input_default_values: bool,
1177    pub review_input_values: bool,
1178    pub is_supervised: bool,
1179}
1180
1181impl RunbookSupervisionContext {
1182    pub fn new() -> Self {
1183        Self {
1184            review_input_default_values: false,
1185            review_input_values: false,
1186            is_supervised: false,
1187        }
1188    }
1189}