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};
16use crate::types::frontend::{LogDetails, LogEvent, StaticLogEvent};
17use crate::types::ConstructDid;
18
19use super::diagnostics::Diagnostic;
20use super::{Did, EvaluatableInput};
21
22#[derive(Clone, Debug, Serialize)]
23#[serde(tag = "type", content = "value", rename_all = "lowercase")]
24pub enum Value {
25 Bool(bool),
26 Null,
27 #[serde(serialize_with = "i128_serializer")]
28 Integer(i128),
29 Float(f64),
30 String(String),
31 Array(Box<Vec<Value>>),
32 Object(IndexMap<String, Value>),
33 #[serde(serialize_with = "hex_serializer")]
34 Buffer(Vec<u8>),
35 #[serde(serialize_with = "addon_serializer")]
36 #[serde(untagged)]
37 Addon(AddonData),
38}
39
40impl PartialEq<Value> for Value {
41 fn eq(&self, other: &Value) -> bool {
42 match (self, other) {
43 (Value::Bool(lhs), Value::Bool(rhs)) => lhs == rhs,
44 (Value::Null, Value::Null) => true,
45 (Value::Integer(lhs), Value::Integer(rhs)) => lhs == rhs,
46 (Value::Float(lhs), Value::Float(rhs)) => lhs == rhs,
47 (Value::String(lhs), Value::String(rhs)) => lhs == rhs,
48 (Value::Buffer(lhs), Value::Buffer(rhs)) => lhs == rhs,
49 (Value::Object(lhs), Value::Object(rhs)) => {
50 if lhs.len() != rhs.len() {
51 return false;
52 }
53 for (k, v) in lhs.iter() {
54 if let Some(r) = rhs.get(k) {
55 if v != r {
56 return false;
57 }
58 } else {
59 return false;
60 }
61 }
62 true
63 }
64 (Value::Array(lhs), Value::Array(rhs)) => {
65 if lhs.len() != rhs.len() {
66 return false;
67 }
68 for (l, r) in lhs.iter().zip(rhs.iter()) {
69 if l != r {
70 return false;
71 }
72 }
73 true
74 }
75 (Value::Addon(lhs), Value::Addon(rhs)) => {
76 if lhs.id != rhs.id {
77 return false;
78 }
79 lhs.bytes == rhs.bytes
80 }
81 _ => false,
82 }
83 }
84}
85
86fn i128_serializer<S>(value: &i128, ser: S) -> Result<S::Ok, S::Error>
87where
88 S: Serializer,
89{
90 ser.serialize_str(&value.to_string())
91}
92
93fn hex_serializer<S>(bytes: &Vec<u8>, ser: S) -> Result<S::Ok, S::Error>
94where
95 S: Serializer,
96{
97 let value = format!("0x{}", hex::encode(&bytes));
98 ser.serialize_str(&value)
99}
100
101fn addon_serializer<S>(addon_data: &AddonData, ser: S) -> Result<S::Ok, S::Error>
102where
103 S: Serializer,
104{
105 let mut map = ser.serialize_map(Some(2))?;
106 map.serialize_entry("type", &addon_data.id)?;
107 let value = format!("0x{}", hex::encode(&addon_data.bytes));
108 map.serialize_entry("value", &value)?;
109 map.end()
110}
111
112impl<'de> Deserialize<'de> for Value {
113 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
114 where
115 D: Deserializer<'de>,
116 {
117 struct ValueVisitor;
118
119 fn decode_hex_string(value: String) -> Result<Vec<u8>, String> {
120 let value = value.replace("0x", "");
121 hex::decode(&value)
122 .map_err(|e| format!("failed to decode hex string ({}) to bytes: {}", value, e))
123 }
124 impl<'de> Visitor<'de> for ValueVisitor {
125 type Value = Value;
126
127 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
128 formatter.write_str("a valid Value")
129 }
130
131 fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
132 where
133 M: MapAccess<'de>,
134 {
135 let mut typing = None;
136 while let Some(key) = map.next_key::<String>()? {
137 match key.as_str() {
138 "type" => {
139 if typing.is_some() {
140 return Err(de::Error::duplicate_field("type"));
141 }
142 let the_typing = map.next_value::<String>()?;
143 if the_typing.eq("null") {
144 return Ok(Value::null());
145 }
146 typing = Some(the_typing);
147 }
148 "value" => {
149 if typing.is_none() {
150 let Some(key) = map.next_key::<String>()? else {
151 return Err(de::Error::missing_field("type"));
152 };
153 match key.as_str() {
154 "type" => {
155 let the_typing = map.next_value::<String>()?;
156 if the_typing.eq("null") {
157 return Ok(Value::null());
158 }
159 typing = Some(the_typing);
160 }
161 unexpected => {
162 return Err(de::Error::custom(format!(
163 "invalid Value: unexpected key {unexpected}"
164 )))
165 }
166 };
167 }
168 let typing = typing.ok_or_else(|| de::Error::missing_field("type"))?;
169 match typing.as_str() {
170 "bool" => return Ok(Value::bool(map.next_value()?)),
171 "integer" => {
172 let value: String = map.next_value()?;
173 let i128 = value.parse().map_err(serde::de::Error::custom)?;
174 return Ok(Value::integer(i128));
175 }
176 "float" => return Ok(Value::float(map.next_value()?)),
177 "string" => return Ok(Value::string(map.next_value()?)),
178 "null" => unreachable!(),
179 "buffer" => {
180 let bytes =
181 decode_hex_string(map.next_value()?).map_err(|e| {
182 de::Error::custom(format!(
183 "failed to deserialize buffer: {e}"
184 ))
185 })?;
186 return Ok(Value::buffer(bytes));
187 }
188 "object" => return Ok(Value::object(map.next_value()?)),
189
190 "array" => return Ok(Value::array(map.next_value()?)),
191 other => {
192 if other.contains("::") {
193 let bytes =
194 decode_hex_string(map.next_value()?).map_err(|e| {
195 de::Error::custom(format!(
196 "failed to deserialize buffer: {e}"
197 ))
198 })?;
199 return Ok(Value::addon(bytes, other));
200 } else {
201 return Err(de::Error::custom(format!(
202 "invalid type {other}"
203 )));
204 }
205 }
206 }
207 }
208 unexpected => {
209 return Err(de::Error::custom(format!(
210 "invalid Value: unexpected key {unexpected}"
211 )));
212 }
213 }
214 }
215
216 Err(de::Error::custom("invalid Value: missing required key value"))
217 }
218 }
219
220 deserializer.deserialize_any(ValueVisitor)
221 }
222}
223
224pub type AddonJsonConverter<'a> = Box<dyn Fn(&Value) -> Result<Option<JsonValue>, Diagnostic> + 'a>;
225
226#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct RunbookCompleteAdditionalInfo {
228 pub construct_did: ConstructDid,
230 pub construct_name: String,
232 pub title: String,
234 pub details: String,
236}
237
238impl RunbookCompleteAdditionalInfo {
239 pub const ADDON_ID: &str = "std::runbook_complete_additional_info";
240
241 pub fn new(
242 construct_did: &ConstructDid,
243 construct_name: impl ToString,
244 title: impl ToString,
245 details: impl ToString,
246 ) -> Self {
247 Self {
248 construct_did: construct_did.clone(),
249 construct_name: construct_name.to_string(),
250 title: title.to_string(),
251 details: details.to_string(),
252 }
253 }
254}
255
256impl Into<Vec<LogEvent>> for RunbookCompleteAdditionalInfo {
257 fn into(self) -> Vec<LogEvent> {
258 self.details
259 .split("\n")
260 .filter_map(|line| {
261 let trimmed = line.trim();
262 if trimmed.is_empty() {
263 None
264 } else {
265 Some(LogEvent::Static(StaticLogEvent {
266 level: super::frontend::LogLevel::Info,
267 details: LogDetails {
268 message: trimmed.to_string(),
269 summary: self.title.clone(),
270 },
271 uuid: self.construct_did.as_uuid(),
272 namespace: self.construct_name.clone(),
273 }))
274 }
275 })
276 .collect()
277 }
278}
279
280impl ToFromValue for RunbookCompleteAdditionalInfo {
281 fn to_value(&self) -> Value {
282 let serialized = serde_json::to_vec(self).unwrap();
283 Value::addon(serialized, RunbookCompleteAdditionalInfo::ADDON_ID)
284 }
285 fn from_value(value: &Value) -> Self {
286 let AddonData { bytes, id } = value.as_addon_data().unwrap();
287 if id != RunbookCompleteAdditionalInfo::ADDON_ID {
288 panic!("Value is not a RunbookCompleteAdditionalInfo");
289 }
290 serde_json::from_slice(bytes).unwrap()
291 }
292}
293
294pub trait ToFromValue {
295 fn to_value(&self) -> Value;
296 fn from_value(value: &Value) -> Self;
297}
298
299impl ToFromValue for Vec<RunbookCompleteAdditionalInfo> {
300 fn to_value(&self) -> Value {
301 let serialized = serde_json::to_vec(self).unwrap();
302 Value::addon(serialized, RunbookCompleteAdditionalInfo::ADDON_ID)
303 }
304 fn from_value(value: &Value) -> Self {
305 let AddonData { bytes, id } = value.as_addon_data().unwrap();
306 if id != RunbookCompleteAdditionalInfo::ADDON_ID {
307 panic!("Value is not a RunbookCompleteAdditionalInfo");
308 }
309 serde_json::from_slice(bytes).unwrap()
310 }
311}
312
313#[derive(Debug, Clone, Serialize, Deserialize)]
314pub enum ThirdPartySignatureStatus {
315 Initialized,
316 Submitted,
317 CheckRequested,
318 Approved,
319 Rejected,
320}
321impl ThirdPartySignatureStatus {
322 pub fn to_bytes(&self) -> Vec<u8> {
323 match self {
324 ThirdPartySignatureStatus::Initialized => vec![0],
325 ThirdPartySignatureStatus::Submitted => vec![1],
326 ThirdPartySignatureStatus::CheckRequested => vec![2],
327 ThirdPartySignatureStatus::Approved => vec![3],
328 ThirdPartySignatureStatus::Rejected => vec![4],
329 }
330 }
331 pub fn from_bytes(bytes: &[u8]) -> Self {
332 match bytes {
333 [0] => ThirdPartySignatureStatus::Initialized,
334 [1] => ThirdPartySignatureStatus::Submitted,
335 [2] => ThirdPartySignatureStatus::CheckRequested,
336 [3] => ThirdPartySignatureStatus::Approved,
337 [4] => ThirdPartySignatureStatus::Rejected,
338 _ => panic!("Invalid bytes for ThirdPartySignatureStatus: {:?}", bytes),
339 }
340 }
341 pub fn is_approved(&self) -> bool {
342 matches!(self, ThirdPartySignatureStatus::Approved)
343 }
344 pub fn is_submitted(&self) -> bool {
345 matches!(self, ThirdPartySignatureStatus::Submitted)
346 }
347 pub fn is_check_requested(&self) -> bool {
348 matches!(self, ThirdPartySignatureStatus::CheckRequested)
349 }
350}
351pub const THIRD_PARTY_SIGNATURE: &str = "std::third_party_signature";
352
353impl Value {
354 pub fn third_party_signature_initialized() -> Self {
355 Value::addon(ThirdPartySignatureStatus::Initialized.to_bytes(), THIRD_PARTY_SIGNATURE)
356 }
357
358 pub fn third_party_signature_submitted() -> Self {
359 Value::addon(ThirdPartySignatureStatus::Submitted.to_bytes(), THIRD_PARTY_SIGNATURE)
360 }
361
362 pub fn third_party_signature_approved() -> Self {
363 Value::addon(ThirdPartySignatureStatus::Approved.to_bytes(), THIRD_PARTY_SIGNATURE)
364 }
365
366 pub fn third_party_signature_rejected() -> Self {
367 Value::addon(ThirdPartySignatureStatus::Rejected.to_bytes(), THIRD_PARTY_SIGNATURE)
368 }
369
370 pub fn third_party_signature_check_requested() -> Self {
371 Value::addon(ThirdPartySignatureStatus::CheckRequested.to_bytes(), THIRD_PARTY_SIGNATURE)
372 }
373
374 pub fn expect_third_party_signature(&self) -> ThirdPartySignatureStatus {
375 if let Value::Addon(addon_data) = self {
376 if addon_data.id == THIRD_PARTY_SIGNATURE {
377 return ThirdPartySignatureStatus::from_bytes(&addon_data.bytes);
378 }
379 }
380 panic!("Value is not a third party signature");
381 }
382
383 pub fn as_third_party_signature_status(&self) -> Option<ThirdPartySignatureStatus> {
384 if let Value::Addon(addon_data) = self {
385 if addon_data.id == THIRD_PARTY_SIGNATURE {
386 return Some(ThirdPartySignatureStatus::from_bytes(&addon_data.bytes));
387 }
388 }
389 None
390 }
391
392 pub fn as_runbook_complete_additional_info(&self) -> Option<RunbookCompleteAdditionalInfo> {
393 if let Value::Addon(addon_data) = self {
394 if addon_data.id == RunbookCompleteAdditionalInfo::ADDON_ID {
395 return Some(RunbookCompleteAdditionalInfo::from_value(&self));
396 }
397 }
398 None
399 }
400}
401
402impl Value {
403 pub fn string(value: String) -> Value {
404 Value::String(value.to_string())
405 }
406 pub fn integer(value: i128) -> Value {
407 Value::Integer(value)
408 }
409 pub fn float(value: f64) -> Value {
410 Value::Float(value)
411 }
412 pub fn null() -> Value {
413 Value::Null
414 }
415 pub fn bool(value: bool) -> Value {
416 Value::Bool(value)
417 }
418 pub fn buffer(bytes: Vec<u8>) -> Value {
419 Value::Buffer(bytes)
420 }
421 pub fn array(array: Vec<Value>) -> Value {
422 Value::Array(Box::new(array))
423 }
424 pub fn object(object: IndexMap<String, Value>) -> Value {
425 Value::Object(object)
426 }
427
428 pub fn addon(bytes: Vec<u8>, id: &str) -> Value {
429 Value::Addon(AddonData { bytes, id: id.to_string() })
430 }
431
432 pub fn expect_string(&self) -> &str {
433 match &self {
434 Value::String(value) => value,
435 _ => unreachable!(),
436 }
437 }
438 pub fn expect_integer(&self) -> i128 {
439 match &self {
440 Value::Integer(value) => *value,
441 _ => unreachable!(),
442 }
443 }
444 pub fn expect_uint(&self) -> Result<u64, String> {
445 match &self {
446 Value::Integer(value) => i128_to_u64(*value),
447 _ => unreachable!(),
448 }
449 }
450 pub fn expect_float(&self) -> f64 {
451 match &self {
452 Value::Float(value) => *value,
453 _ => unreachable!(),
454 }
455 }
456 pub fn expect_null(&self) -> () {
457 match &self {
458 Value::Null => (),
459 _ => unreachable!(),
460 }
461 }
462 pub fn expect_bool(&self) -> bool {
463 match &self {
464 Value::Bool(value) => *value,
465 _ => unreachable!(),
466 }
467 }
468 pub fn expect_buffer_data(&self) -> &Vec<u8> {
469 match &self {
470 Value::Buffer(value) => &value,
471 _ => unreachable!(),
472 }
473 }
474 pub fn expect_addon_data(&self) -> &AddonData {
475 match &self {
476 Value::Addon(value) => &value,
477 _ => unreachable!(),
478 }
479 }
480
481 #[deprecated(note = "use `get_buffer_bytes_result` instead")]
482 pub fn expect_buffer_bytes(&self) -> Vec<u8> {
483 self.try_get_buffer_bytes_result().unwrap().expect("unable to retrieve bytes")
484 }
485
486 pub fn get_buffer_bytes_result(&self) -> Result<Vec<u8>, String> {
487 self.try_get_buffer_bytes_result()?.ok_or("unable to retrieve bytes".into())
488 }
489
490 #[deprecated(note = "use `try_get_buffer_bytes_result` instead")]
491 pub fn try_get_buffer_bytes(&self) -> Option<Vec<u8>> {
492 let bytes = match &self {
493 Value::Buffer(value) => value.clone(),
494 Value::String(bytes) => {
495 let bytes = if bytes.starts_with("0x") {
496 crate::hex::decode(&bytes[2..]).unwrap()
497 } else {
498 crate::hex::decode(&bytes).unwrap()
499 };
500 bytes
501 }
502 Value::Array(values) => {
503 values.iter().flat_map(|v| v.get_buffer_bytes_result().unwrap()).collect()
504 }
505 Value::Addon(addon_value) => addon_value.bytes.clone(),
506 _ => return None,
507 };
508
509 Some(bytes)
510 }
511
512 pub fn try_get_buffer_bytes_result(&self) -> Result<Option<Vec<u8>>, String> {
513 let bytes = match &self {
514 Value::Buffer(value) => value.clone(),
515 Value::String(bytes) => {
516 let stripped = if bytes.starts_with("0x") { &bytes[2..] } else { &bytes[..] };
517 let bytes = crate::hex::decode(stripped).map_err(|e| {
518 format!("string '{}' could not be decoded to hex bytes: {}", bytes, e)
519 })?;
520 bytes
521 }
522 Value::Array(values) => values
523 .iter()
524 .map(|v| v.try_get_buffer_bytes_result())
525 .collect::<Result<Vec<Option<_>>, String>>()?
526 .into_iter()
527 .filter_map(|v| v)
528 .flat_map(|v| v)
529 .collect(),
530 Value::Addon(addon_value) => addon_value.bytes.clone(),
531 _ => return Ok(None),
532 };
533
534 Ok(Some(bytes))
535 }
536 pub fn expect_array(&self) -> &Box<Vec<Value>> {
537 match &self {
538 Value::Array(value) => value,
539 _ => unreachable!(),
540 }
541 }
542
543 pub fn expect_object(&self) -> &IndexMap<String, Value> {
544 match &self {
545 Value::Object(value) => value,
546 _ => unreachable!(),
547 }
548 }
549
550 pub fn as_string(&self) -> Option<&str> {
551 match &self {
552 Value::String(value) => Some(value),
553 _ => None,
554 }
555 }
556 pub fn as_integer(&self) -> Option<i128> {
557 match &self {
558 Value::Integer(value) => Some(*value),
559 _ => None,
560 }
561 }
562 pub fn as_uint(&self) -> Option<Result<u64, String>> {
563 match &self {
564 Value::Integer(value) => Some(i128_to_u64(*value)),
565 _ => None,
566 }
567 }
568 pub fn as_u8(&self) -> Option<Result<u8, String>> {
569 match &self {
570 Value::Integer(value) => {
571 Some(u8::try_from(*value).map_err(|e| format!("invalid u8: {e}")))
572 }
573 _ => None,
574 }
575 }
576 pub fn as_u16(&self) -> Option<Result<u16, String>> {
577 match &self {
578 Value::Integer(value) => {
579 Some(u16::try_from(*value).map_err(|e| format!("invalid u16: {e}")))
580 }
581 _ => None,
582 }
583 }
584 pub fn as_float(&self) -> Option<f64> {
585 match &self {
586 Value::Float(value) => Some(*value),
587 _ => None,
588 }
589 }
590 pub fn as_null(&self) -> Option<()> {
591 match &self {
592 Value::Null => Some(()),
593 _ => None,
594 }
595 }
596 pub fn as_bool(&self) -> Option<bool> {
597 match &self {
598 Value::Bool(value) => Some(*value),
599 _ => None,
600 }
601 }
602 pub fn as_buffer_data(&self) -> Option<&Vec<u8>> {
603 match &self {
604 Value::Buffer(value) => Some(&value),
605 _ => None,
606 }
607 }
608 pub fn as_addon_data(&self) -> Option<&AddonData> {
609 match &self {
610 Value::Addon(value) => Some(&value),
611 _ => None,
612 }
613 }
614 pub fn as_array(&self) -> Option<&Box<Vec<Value>>> {
615 match &self {
616 Value::Array(value) => Some(value),
617 _ => None,
618 }
619 }
620
621 pub fn as_map(&self) -> Option<&Box<Vec<Value>>> {
622 match &self {
623 Value::Array(value) => Some(value),
624 _ => None,
625 }
626 }
627
628 pub fn as_object(&self) -> Option<&IndexMap<String, Value>> {
629 match &self {
630 Value::Object(value) => Some(value),
631 _ => None,
632 }
633 }
634
635 pub fn as_object_mut(&mut self) -> Option<&mut IndexMap<String, Value>> {
636 match self {
637 Value::Object(value) => Some(value),
638 _ => None,
639 }
640 }
641
642 pub fn get_keys_from_object(&self, mut keys: VecDeque<String>) -> Result<Value, Diagnostic> {
643 let Some(key) = keys.pop_front() else {
644 return Ok(self.clone());
645 };
646
647 if let Some(ref object) = self.as_object() {
648 match object.get(&key) {
649 Some(val) => val.get_keys_from_object(keys),
650 None => {
651 Err(Diagnostic::error_from_string(format!("missing key '{}' from object", key)))
652 }
653 }
654 } else {
655 Err(Diagnostic::error_from_string(format!("invalid key '{}' for object", key)))
656 }
657 }
658
659 pub fn is_type_eq(&self, rhs: &Value) -> bool {
660 match (self, rhs) {
661 (Value::Null, Value::Null) => true,
662 (Value::Bool(_), Value::Bool(_)) => true,
663 (Value::Integer(_), Value::Integer(_)) => true,
664 (Value::Float(_), Value::Float(_)) => true,
665 (Value::String(_), Value::String(_)) => true,
666 (Value::Buffer(_), Value::Buffer(_)) => true,
667 (Value::Object(_), Value::Object(_)) => true,
668 (Value::Null, _) => false,
669 (Value::Bool(_), _) => false,
670 (Value::Integer(_), _) => false,
671 (Value::Float(_), _) => false,
672 (Value::String(_), _) => false,
673 (Value::Buffer(_), _) => false,
674 (Value::Object(_), _) => false,
675 (Value::Array(lhs), Value::Array(rhs)) => {
676 let Some(first_lhs) = lhs.first() else {
677 return false;
678 };
679 let Some(first_rhs) = rhs.first() else {
680 return false;
681 };
682 first_lhs.is_type_eq(first_rhs)
683 }
684 (Value::Array(_), _) => false,
685 (Value::Addon(lhs), Value::Addon(rhs)) => lhs.id == rhs.id,
686 (Value::Addon(_), _) => false,
687 }
688 }
689 pub fn to_be_bytes(&self) -> Vec<u8> {
690 match &self {
691 Value::Buffer(bytes) => bytes.clone(),
692 Value::Array(values) => {
693 let mut joined = vec![];
694 for value in values.iter() {
695 joined.extend(value.to_be_bytes());
696 }
697 joined
698 }
699 Value::String(bytes) => {
700 let bytes = if bytes.starts_with("0x") {
701 crate::hex::decode(&bytes[2..]).unwrap()
702 } else {
703 match crate::hex::decode(&bytes) {
704 Ok(res) => res,
705 Err(_) => bytes.as_bytes().to_vec(),
706 }
707 };
708 bytes
709 }
710 Value::Addon(data) => data.bytes.clone(),
711 Value::Integer(value) => value.to_be_bytes().to_vec(),
712 Value::Float(value) => value.to_be_bytes().to_vec(),
713 Value::Bool(value) => vec![*value as u8],
714 Value::Null => vec![],
715 Value::Object(values) => {
716 let mut joined = vec![];
717 for (key, value) in values.iter() {
718 joined.extend(key.as_bytes());
719 joined.extend(value.to_be_bytes());
720 }
721 joined
722 }
723 }
724 }
725
726 pub fn to_le_bytes(&self) -> Vec<u8> {
727 match &self {
728 Value::Buffer(bytes) => bytes.clone(),
729 Value::Array(values) => {
730 let mut joined = vec![];
731 for value in values.iter() {
732 joined.extend(value.to_le_bytes());
733 }
734 joined
735 }
736 Value::String(bytes) => {
737 let bytes = if bytes.starts_with("0x") {
738 crate::hex::decode(&bytes[2..]).unwrap()
739 } else {
740 match crate::hex::decode(&bytes) {
741 Ok(res) => res,
742 Err(_) => bytes.as_bytes().to_vec(),
743 }
744 };
745 bytes
746 }
747 Value::Addon(data) => data.bytes.clone(),
748 Value::Integer(value) => value.to_le_bytes().to_vec(),
749 Value::Float(value) => value.to_le_bytes().to_vec(),
750 Value::Bool(value) => vec![*value as u8],
751 Value::Null => vec![],
752 Value::Object(values) => {
753 let mut joined = vec![];
754 for (key, value) in values.iter() {
755 joined.extend(key.as_bytes());
756 joined.extend(value.to_le_bytes());
757 }
758 joined
759 }
760 }
761 }
762
763 pub fn parse_and_default_to_string(value_str: &str) -> Value {
764 let trim = value_str.trim();
765 let value = match trim.parse::<i128>() {
766 Ok(uint) => Value::integer(uint),
767 Err(_) => {
768 if trim.starts_with("[") || trim.starts_with("(") {
769 let values_to_parse = trim[1..trim.len() - 1].split(",").collect::<Vec<_>>();
770 let mut values = vec![];
771 for v in values_to_parse.iter() {
772 values.push(Value::parse_and_default_to_string(v));
773 }
774 Value::array(values)
775 } else {
776 Value::string(trim.into())
777 }
778 }
779 };
780 value
781 }
782
783 pub fn compute_fingerprint(&self) -> Did {
784 let bytes = self.to_be_bytes();
785 Did::from_components(vec![bytes])
786 }
787
788 pub fn to_json(&self, addon_converters: Option<&Vec<AddonJsonConverter>>) -> JsonValue {
789 let json = match self {
790 Value::Bool(b) => JsonValue::Bool(*b),
791 Value::Null => JsonValue::Null,
792 Value::Integer(i) => JsonValue::Number(serde_json::Number::from(*i as i64)),
793 Value::Float(f) => JsonValue::Number(serde_json::Number::from_f64(*f).unwrap()),
794 Value::String(s) => JsonValue::String(s.to_string()),
795 Value::Array(vec) => JsonValue::Array(
796 vec.iter().map(|v| v.to_json(addon_converters)).collect::<Vec<JsonValue>>(),
797 ),
798 Value::Object(index_map) => JsonValue::Object(
799 index_map
800 .iter()
801 .map(|(k, v)| (k.clone(), v.to_json(addon_converters)))
802 .collect::<Map<String, JsonValue>>(),
803 ),
804 Value::Buffer(vec) => JsonValue::String(format!("0x{}", hex::encode(&vec))),
805 Value::Addon(addon_data) => {
806 if let Some(addon_converters) = addon_converters.as_ref() {
807 let parsed_values = addon_converters
808 .iter()
809 .filter_map(|converter| converter(self).ok().flatten())
810 .collect::<Vec<_>>();
811 if let Some(parsed_value) = parsed_values.first() {
812 return parsed_value.clone();
813 }
814 }
815 JsonValue::String(addon_data.to_string())
816 }
817 };
818 json
819 }
820}
821
822fn i128_to_u64(i128: i128) -> Result<u64, String> {
823 u64::try_from(i128).map_err(|e| format!("invalid uint: {e}"))
824}
825impl Value {
826 pub fn to_string(&self) -> String {
827 match self {
828 Value::String(val) => val.clone(),
829 Value::Bool(val) => val.to_string(),
830 Value::Integer(val) => val.to_string(),
831 Value::Float(val) => val.to_string(),
832 Value::Null => "null".to_string(),
833 Value::Buffer(bytes) => {
834 format!("0x{}", hex::encode(&bytes))
835 }
836 Value::Object(obj) => {
837 let mut res = "{".to_string();
838 let len = obj.len();
839 for (i, (k, v)) in obj.iter().enumerate() {
840 res.push_str(&format!(
841 r#""{}": {}{}"#,
842 k,
843 v.to_string(),
844 if i == (len - 1) { "" } else { "," }
845 ));
846 }
847 res
848 }
849 Value::Array(array) => {
850 format!("[{}]", array.iter().map(|e| e.to_string()).collect::<Vec<_>>().join(", "))
851 }
852 Value::Addon(addon_value) => addon_value.to_string(),
853 }
854 }
855
856 pub fn encode_to_string(&self) -> String {
861 match self {
862 Value::String(val) => format!(r#""{val}""#),
863 Value::Bool(val) => val.to_string(),
864 Value::Integer(val) => val.to_string(),
865 Value::Float(val) => val.to_string(),
866 Value::Null => "null".to_string(),
867 Value::Buffer(bytes) => {
868 format!(r#""0x{}""#, hex::encode(&bytes))
869 }
870 Value::Object(obj) => {
871 let mut res = "{".to_string();
872 let len = obj.len();
873 for (i, (k, v)) in obj.iter().enumerate() {
874 res.push_str(&format!(
875 r#"
876 "{}": {}{}"#,
877 k,
878 v.encode_to_string(),
879 if i == (len - 1) { "" } else { "," }
880 ));
881 }
882 res.push_str(&format!(
883 r#"
884}}"#
885 ));
886 res
887 }
888 Value::Array(array) => {
889 format!(
890 "[{}]",
891 array.iter().map(|e| e.encode_to_string()).collect::<Vec<_>>().join(", ")
892 )
893 }
894 Value::Addon(addon_value) => addon_value.encode_to_string(),
895 }
896 }
897
898 pub fn from_jaq_value(value: &Val) -> Result<Value, String> {
899 let res = match value {
900 Val::Null => Value::null(),
901 Val::Bool(val) => Value::bool(*val),
902 Val::Num(val) => val
903 .parse::<i128>()
904 .map(Value::integer)
905 .map_err(|e| format!("Failed to parse number: {}", e))?,
906 Val::Int(val) => i128::try_from(*val)
907 .map(Value::integer)
908 .map_err(|e| format!("Failed to convert integer: {}", e))?,
909 Val::Float(val) => Value::float(*val),
910 Val::Str(val) => Value::string(val.to_string()),
911 Val::Arr(val) => Value::array(
912 val.iter()
913 .map(|v| Value::from_jaq_value(v))
914 .collect::<Result<Vec<Value>, String>>()?,
915 ),
916 Val::Obj(val) => ObjectType::from(
917 val.iter()
918 .map(|(k, v)| Value::from_jaq_value(v).map(|v| (k.as_str(), v)))
919 .collect::<Result<Vec<(&str, Value)>, String>>()?,
920 )
921 .to_value(),
922 };
923 Ok(res)
924 }
925 pub fn get_type(&self) -> Type {
926 match self {
927 Value::Bool(_) => Type::Bool,
928 Value::Null => Type::null(),
929 Value::Integer(_) => Type::Integer,
930 Value::Float(_) => Type::Float,
931 Value::String(_) => Type::String,
932 Value::Buffer(_) => Type::Buffer,
933 Value::Object(_) => Type::Object(ObjectDefinition::arbitrary()),
934 Value::Array(t) => {
935 Type::Array(Box::new(t.first().unwrap_or(&Value::null()).get_type()))
936 }
937 Value::Addon(t) => Type::Addon(t.id.clone()),
938 }
939 }
940}
941
942#[derive(Clone, Debug)]
970pub struct ObjectType {
971 map: IndexMap<String, Value>,
972}
973impl ObjectType {
974 pub fn new() -> Self {
975 ObjectType { map: IndexMap::new() }
976 }
977
978 pub fn from_map(map: IndexMap<String, Value>) -> Self {
979 ObjectType { map }
980 }
981
982 pub fn from<S: ToString, T: IntoIterator<Item = (S, Value)>>(default: T) -> Self {
983 let mut map = IndexMap::new();
984 for (key, value) in default {
985 map.insert(key.to_string(), value);
986 }
987 ObjectType { map }
988 }
989
990 pub fn insert(&mut self, key: &str, value: Value) -> &mut Self {
991 self.map.insert(key.to_string(), value);
992 self
993 }
994
995 pub fn inner(&self) -> IndexMap<String, Value> {
996 self.map.clone()
997 }
998 pub fn to_value(&self) -> Value {
999 Value::object(self.map.clone())
1000 }
1001}
1002
1003#[derive(Clone, Serialize, Deserialize, PartialEq)]
1004pub struct AddonData {
1005 pub bytes: Vec<u8>,
1006 pub id: String,
1007}
1008impl AddonData {
1009 pub fn to_string(&self) -> String {
1010 format!("0x{}", hex::encode(&self.bytes))
1011 }
1012 pub fn encode_to_string(&self) -> String {
1013 format!(r#""0x{}""#, hex::encode(&self.bytes))
1014 }
1015}
1016
1017impl fmt::Debug for AddonData {
1018 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1019 f.debug_struct("AddonData").field("bytes", &self.to_string()).field("id", &self.id).finish()
1021 }
1022}
1023
1024#[derive(Clone, Debug, Eq, PartialEq, Hash)]
1025pub enum Type {
1026 Bool,
1027 Null(Option<Box<Type>>),
1028 Integer,
1029 Float,
1030 String,
1031 Buffer,
1032 Object(ObjectDefinition),
1033 Addon(String),
1034 Array(Box<Type>),
1035 Map(ObjectDefinition),
1036}
1037
1038impl Type {
1039 pub fn string() -> Type {
1040 Type::String
1041 }
1042 pub fn integer() -> Type {
1043 Type::Integer
1044 }
1045 pub fn float() -> Type {
1046 Type::Float
1047 }
1048 pub fn null() -> Type {
1049 Type::Null(None)
1050 }
1051 pub fn typed_null(inner: Type) -> Type {
1052 Type::Null(Some(Box::new(inner)))
1053 }
1054 pub fn bool() -> Type {
1055 Type::Bool
1056 }
1057 pub fn object(def: ObjectDefinition) -> Type {
1058 Type::Object(def)
1059 }
1060 pub fn strict_object(props: Vec<ObjectProperty>) -> Type {
1061 Type::Object(ObjectDefinition::strict(props))
1062 }
1063 pub fn arbitrary_object() -> Type {
1064 Type::Object(ObjectDefinition::arbitrary())
1065 }
1066 pub fn documented_arbitrary_object(props: Vec<ObjectProperty>) -> Type {
1067 Type::Object(ObjectDefinition::documented_arbitrary(props))
1068 }
1069 pub fn map(def: ObjectDefinition) -> Type {
1070 Type::Map(def)
1071 }
1072 pub fn strict_map(props: Vec<ObjectProperty>) -> Type {
1073 Type::Map(ObjectDefinition::strict(props))
1074 }
1075 pub fn arbitrary_map() -> Type {
1076 Type::Map(ObjectDefinition::arbitrary())
1077 }
1078 pub fn documented_arbitrary_map(props: Vec<ObjectProperty>) -> Type {
1079 Type::Map(ObjectDefinition::documented_arbitrary(props))
1080 }
1081 pub fn buffer() -> Type {
1082 Type::Buffer
1083 }
1084 pub fn addon(id: &str) -> Type {
1085 Type::Addon(id.to_string())
1086 }
1087 pub fn array(array_item_type: Type) -> Type {
1088 Type::Array(Box::new(array_item_type))
1089 }
1090
1091 pub fn check_value(&self, value: &Value) -> Result<(), Diagnostic> {
1092 let mismatch_err = |expected: &str| {
1093 Diagnostic::error_from_string(format!(
1094 "expected {}, got {}",
1095 expected,
1096 value.get_type().to_string()
1097 ))
1098 };
1099
1100 match &self {
1101 Type::Bool => value.as_bool().map(|_| ()).ok_or_else(|| mismatch_err("bool"))?,
1102 Type::Null(inner) => {
1103 if let Some(inner) = inner {
1104 value
1105 .as_null()
1106 .map(|_| ())
1107 .ok_or_else(|| mismatch_err(&format!("null<{}>", inner.to_string())))?
1108 } else {
1109 value.as_null().map(|_| ()).ok_or_else(|| mismatch_err("null"))?
1110 }
1111 }
1112 Type::Integer => {
1113 value.as_integer().map(|_| ()).ok_or_else(|| mismatch_err("integer"))?
1114 }
1115 Type::Float => value.as_float().map(|_| ()).ok_or_else(|| mismatch_err("float"))?,
1116 Type::String => value.as_string().map(|_| ()).ok_or_else(|| mismatch_err("string"))?,
1117 Type::Buffer => {
1118 value.as_buffer_data().map(|_| ()).ok_or_else(|| mismatch_err("buffer"))?
1119 }
1120 Type::Addon(addon_type) => value
1121 .as_addon_data()
1122 .map(|_| ())
1123 .ok_or_else(|| mismatch_err(&format!("addon type '{}'", addon_type)))?,
1124 Type::Array(array_type) => value
1125 .as_array()
1126 .map(|_| ())
1127 .ok_or_else(|| mismatch_err(&format!("array<{}>", array_type.to_string())))?,
1128 Type::Object(object_def) | Type::Map(object_def) => match object_def {
1129 ObjectDefinition::Strict(props) => {
1130 let object = value.as_object().ok_or_else(|| mismatch_err("object"))?;
1131 for expected_prop in props.iter() {
1132 let prop_value = object.get(&expected_prop.name);
1133 if expected_prop.optional && prop_value.is_none() {
1134 continue;
1135 }
1136 let prop_value = prop_value.ok_or_else(|| {
1137 Diagnostic::error_from_string(format!(
1138 "missing required property '{}'",
1139 expected_prop.name,
1140 ))
1141 })?;
1142 expected_prop.typing.check_value(prop_value).map_err(|e| {
1143 Diagnostic::error_from_string(format!(
1144 "object property '{}': {}",
1145 expected_prop.name, e.message
1146 ))
1147 })?;
1148 }
1149 }
1150 ObjectDefinition::Arbitrary(_) => {
1151 let _ = value.as_object().ok_or_else(|| mismatch_err("object"))?;
1152 }
1153 ObjectDefinition::Tuple(_) | ObjectDefinition::Enum(_) => {
1154 unimplemented!("ObjectDefinition::Tuple and ObjectDefinition::Enum are not supported for runbook types");
1155 }
1156 }, };
1158 Ok(())
1159 }
1160
1161 pub fn as_object(&self) -> Option<&ObjectDefinition> {
1162 match self {
1163 Type::Object(props) => Some(props),
1164 _ => None,
1165 }
1166 }
1167
1168 pub fn as_array(&self) -> Option<&Box<Type>> {
1169 match self {
1170 Type::Array(typing) => Some(typing),
1171 _ => None,
1172 }
1173 }
1174
1175 pub fn as_map(&self) -> Option<&ObjectDefinition> {
1176 match self {
1177 Type::Map(props) => Some(props),
1178 _ => None,
1179 }
1180 }
1181
1182 pub fn as_action(&self) -> Option<&String> {
1183 match self {
1184 Type::Addon(action) => Some(action),
1185 _ => None,
1186 }
1187 }
1188
1189 pub fn get_expressions_referencing_constructs<'a>(
1196 &self,
1197 block: &Block,
1198 input: Box<dyn EvaluatableInput>,
1199 dependencies: &mut Vec<(Option<Box<dyn EvaluatableInput>>, Expression)>,
1200 ) {
1201 let input_name = input.name();
1202 match self {
1203 Type::Map(ref object_def) => match object_def {
1204 ObjectDefinition::Strict(props) => {
1205 for block in block.body.get_blocks(&input_name) {
1206 for prop in props.iter() {
1207 let res = visit_optional_untyped_attribute(&prop.name, &block);
1208 if let Some(expr) = res {
1209 collect_constructs_references_from_expression(
1210 &expr,
1211 Some(input.clone()),
1212 dependencies,
1213 );
1214 }
1215 }
1216 }
1217 }
1218 ObjectDefinition::Arbitrary(_) => {
1219 for block in block.body.get_blocks(&input_name) {
1220 collect_constructs_references_from_block(
1221 block,
1222 Some(input.clone()),
1223 dependencies,
1224 );
1225 }
1226 }
1227 ObjectDefinition::Tuple(_) | ObjectDefinition::Enum(_) => {
1228 unimplemented!("ObjectDefinition::Tuple and ObjectDefinition::Enum are not supported for runbook types");
1229 }
1230 },
1231 Type::Object(ref object_def) => {
1232 if let Some(expr) = visit_optional_untyped_attribute(&input_name, &block) {
1233 collect_constructs_references_from_expression(
1234 &expr,
1235 Some(input.clone()),
1236 dependencies,
1237 );
1238 }
1239 match object_def {
1240 ObjectDefinition::Strict(props) => {
1241 for prop in props.iter() {
1242 for block in block.body.get_blocks(&input_name) {
1243 if let Some(expr) =
1244 visit_optional_untyped_attribute(&prop.name, &block)
1245 {
1246 collect_constructs_references_from_expression(
1247 &expr,
1248 Some(input.clone()),
1249 dependencies,
1250 );
1251 }
1252 }
1253 }
1254 }
1255 ObjectDefinition::Arbitrary(_) => {
1256 for block in block.body.get_blocks(&input_name) {
1257 collect_constructs_references_from_block(
1258 block,
1259 Some(input.clone()),
1260 dependencies,
1261 );
1262 }
1263 }
1264 ObjectDefinition::Tuple(_) | ObjectDefinition::Enum(_) => {
1265 unimplemented!("ObjectDefinition::Tuple and ObjectDefinition::Enum are not supported for runbook types");
1266 }
1267 }
1268 }
1269 _ => {
1270 if let Some(expr) = visit_optional_untyped_attribute(&input_name, &block) {
1271 collect_constructs_references_from_expression(&expr, Some(input), dependencies);
1272 }
1273 }
1274 }
1275 }
1276}
1277
1278impl Type {
1279 pub fn to_string(&self) -> String {
1280 match self {
1281 Type::Bool => "bool".into(),
1282 Type::Null(inner) => {
1283 if let Some(inner) = inner {
1284 format!("null<{}>", inner.to_string())
1285 } else {
1286 "null".into()
1287 }
1288 }
1289 Type::Integer => "integer".into(),
1290 Type::Float => "float".into(),
1291 Type::String => "string".into(),
1292 Type::Buffer => "buffer".into(),
1293 Type::Object(_) => "object".into(),
1294 Type::Addon(addon) => format!("addon({})", addon),
1295 Type::Array(typing) => format!("array[{}]", typing.to_string()),
1296 Type::Map(_) => "map".into(),
1297 }
1298 }
1299}
1300
1301impl Default for Type {
1302 fn default() -> Self {
1303 Type::string()
1304 }
1305}
1306impl TryFrom<String> for Type {
1307 type Error = String;
1308 fn try_from(value: String) -> Result<Self, Self::Error> {
1309 let val = match value.as_str() {
1310 "string" => Type::String,
1311 "integer" => Type::Integer,
1312 "float" => Type::Float,
1313 "bool" => Type::Bool,
1314 "buffer" => Type::Buffer,
1315 "object" => Type::Object(ObjectDefinition::arbitrary()),
1316 other => {
1317 if other == "null" {
1318 return Ok(Type::null());
1319 }
1320 if other.starts_with("null<") && other.ends_with(">") {
1321 let mut inner = other.replace("null<", "");
1322 inner = inner.replace(">", "");
1323 let inner_type = Type::try_from(inner)?;
1324 return Ok(Type::typed_null(inner_type));
1325 } else if other.starts_with("array[") && other.ends_with("]") {
1326 let mut inner = other.replace("array[", "");
1327 inner = inner.replace("]", "");
1328 return Type::try_from(inner);
1329 } else if other.starts_with("addon(") {
1330 let mut inner = other.replace("addon(", "");
1331 inner = inner.replace(")", "");
1332 Type::addon(&inner)
1333 } else {
1334 return Err(format!("invalid type: {}", other));
1335 }
1336 }
1337 };
1338 Ok(val)
1339 }
1340}
1341
1342impl Serialize for Type {
1343 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1344 where
1345 S: Serializer,
1346 {
1347 serializer.serialize_str(&self.to_string())
1348 }
1349}
1350
1351impl<'de> Deserialize<'de> for Type {
1352 fn deserialize<D>(deserializer: D) -> Result<Type, D::Error>
1353 where
1354 D: Deserializer<'de>,
1355 {
1356 let type_str: String = serde::Deserialize::deserialize(deserializer)?;
1357 let t = Type::try_from(type_str).map_err(serde::de::Error::custom)?;
1358 Ok(t)
1359 }
1360}
1361
1362#[derive(Clone, Debug, Eq, PartialEq, Hash)]
1363pub enum ObjectDefinition {
1364 Strict(Vec<ObjectProperty>),
1366 Arbitrary(Option<Vec<ObjectProperty>>),
1370 Tuple(Vec<ObjectProperty>),
1373 Enum(Vec<ObjectProperty>),
1376}
1377
1378impl ObjectDefinition {
1379 pub fn strict(props: Vec<ObjectProperty>) -> Self {
1380 ObjectDefinition::Strict(props)
1381 }
1382
1383 pub fn arbitrary() -> Self {
1384 ObjectDefinition::Arbitrary(None)
1385 }
1386
1387 pub fn documented_arbitrary(props: Vec<ObjectProperty>) -> Self {
1388 ObjectDefinition::Arbitrary(Some(props))
1389 }
1390
1391 pub fn tuple(props: Vec<ObjectProperty>) -> Self {
1392 ObjectDefinition::Tuple(props)
1393 }
1394
1395 pub fn enum_type(props: Vec<ObjectProperty>) -> Self {
1396 ObjectDefinition::Enum(props)
1397 }
1398
1399 pub fn join_documentation(&self, recursion_depth: usize) -> String {
1400 match self {
1401 ObjectDefinition::Strict(props) | ObjectDefinition::Arbitrary(Some(props)) => props
1402 .iter()
1403 .map(|prop| {
1404 format!(
1405 "{}- **{}**: {}",
1406 " ".repeat((recursion_depth + 1) * 2),
1407 prop.name,
1408 prop.join_documentation(recursion_depth + 1)
1409 )
1410 })
1411 .collect::<Vec<String>>()
1412 .join("\n"),
1413 ObjectDefinition::Arbitrary(None) => String::new(),
1414 _ => {
1415 String::new()
1418 }
1419 }
1420 }
1421}
1422
1423#[derive(Clone, Debug, Eq, PartialEq, Hash)]
1424pub struct ObjectProperty {
1425 pub name: String,
1426 pub documentation: String,
1427 pub typing: Type,
1428 pub optional: bool,
1429 pub tainting: bool,
1430 pub internal: bool,
1431}
1432
1433impl ObjectProperty {
1434 pub fn join_documentation(&self, recursion_depth: usize) -> String {
1435 match &self.typing {
1436 Type::Object(object_definition) => {
1437 format!(
1438 "{} This is an object type containing the keys:\n{}",
1439 self.documentation,
1440 object_definition.join_documentation(recursion_depth)
1441 )
1442 }
1443 Type::Map(object_definition) => {
1444 format!(
1445 "{} This is a map type containing the keys:\n{}",
1446 self.documentation,
1447 object_definition.join_documentation(recursion_depth)
1448 )
1449 }
1450 _ => self.documentation.clone(),
1451 }
1452 }
1453}
1454
1455#[derive(Clone, Debug)]
1456pub struct RunbookSupervisionContext {
1457 pub review_input_default_values: bool,
1458 pub review_input_values: bool,
1459 pub is_supervised: bool,
1460}
1461
1462impl RunbookSupervisionContext {
1463 pub fn new() -> Self {
1464 Self {
1465 review_input_default_values: false,
1466 review_input_values: false,
1467 is_supervised: false,
1468 }
1469 }
1470}