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 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#[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 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 }, };
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 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(Vec<ObjectProperty>),
1104 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}