1use std::cmp::Ordering;
4use std::fmt;
5use std::hash::Hash;
6use std::hash::Hasher;
7use std::path::Path;
8use std::sync::Arc;
9
10use anyhow::Context;
11use anyhow::Result;
12use anyhow::anyhow;
13use anyhow::bail;
14use indexmap::IndexMap;
15use itertools::Either;
16use ordered_float::OrderedFloat;
17use path_clean::PathClean;
18use serde::ser::SerializeMap;
19use serde::ser::SerializeSeq;
20use wdl_analysis::stdlib::STDLIB as ANALYSIS_STDLIB;
21use wdl_analysis::types::ArrayType;
22use wdl_analysis::types::CallType;
23use wdl_analysis::types::Coercible as _;
24use wdl_analysis::types::CompoundType;
25use wdl_analysis::types::Optional;
26use wdl_analysis::types::PrimitiveType;
27use wdl_analysis::types::Type;
28use wdl_ast::AstToken;
29use wdl_ast::TreeNode;
30use wdl_ast::v1;
31use wdl_ast::v1::TASK_FIELD_ATTEMPT;
32use wdl_ast::v1::TASK_FIELD_CONTAINER;
33use wdl_ast::v1::TASK_FIELD_CPU;
34use wdl_ast::v1::TASK_FIELD_DISKS;
35use wdl_ast::v1::TASK_FIELD_END_TIME;
36use wdl_ast::v1::TASK_FIELD_EXT;
37use wdl_ast::v1::TASK_FIELD_FPGA;
38use wdl_ast::v1::TASK_FIELD_GPU;
39use wdl_ast::v1::TASK_FIELD_ID;
40use wdl_ast::v1::TASK_FIELD_MEMORY;
41use wdl_ast::v1::TASK_FIELD_META;
42use wdl_ast::v1::TASK_FIELD_NAME;
43use wdl_ast::v1::TASK_FIELD_PARAMETER_META;
44use wdl_ast::v1::TASK_FIELD_RETURN_CODE;
45use wdl_grammar::lexer::v1::is_ident;
46
47use crate::EvaluationContext;
48use crate::Outputs;
49use crate::TaskExecutionConstraints;
50use crate::path;
51
52pub trait Coercible: Sized {
54 fn coerce(&self, target: &Type) -> Result<Self>;
58}
59
60#[derive(Debug, Clone)]
64pub enum Value {
65 None,
67 Primitive(PrimitiveValue),
69 Compound(CompoundValue),
71 Task(TaskValue),
76 Hints(HintsValue),
80 Input(InputValue),
84 Output(OutputValue),
88 Call(CallValue),
90}
91
92impl Value {
93 pub fn from_v1_metadata<N: TreeNode>(value: &v1::MetadataValue<N>) -> Self {
99 match value {
100 v1::MetadataValue::Boolean(v) => v.value().into(),
101 v1::MetadataValue::Integer(v) => v.value().expect("number should be in range").into(),
102 v1::MetadataValue::Float(v) => v.value().expect("number should be in range").into(),
103 v1::MetadataValue::String(v) => PrimitiveValue::new_string(
104 v.text()
105 .expect("metadata strings shouldn't have placeholders")
106 .text(),
107 )
108 .into(),
109 v1::MetadataValue::Null(_) => Self::None,
110 v1::MetadataValue::Object(o) => Object::from_v1_metadata(o.items()).into(),
111 v1::MetadataValue::Array(a) => Array::new_unchecked(
112 ANALYSIS_STDLIB.array_object_type().clone(),
113 a.elements().map(|v| Value::from_v1_metadata(&v)).collect(),
114 )
115 .into(),
116 }
117 }
118
119 pub fn ty(&self) -> Type {
121 match self {
122 Self::None => Type::None,
123 Self::Primitive(v) => v.ty(),
124 Self::Compound(v) => v.ty(),
125 Self::Task(_) => Type::Task,
126 Self::Hints(_) => Type::Hints,
127 Self::Input(_) => Type::Input,
128 Self::Output(_) => Type::Output,
129 Self::Call(v) => Type::Call(v.ty.clone()),
130 }
131 }
132
133 pub fn is_none(&self) -> bool {
135 matches!(self, Self::None)
136 }
137
138 pub fn as_primitive(&self) -> Option<&PrimitiveValue> {
142 match self {
143 Self::Primitive(v) => Some(v),
144 _ => None,
145 }
146 }
147
148 pub fn as_compound(&self) -> Option<&CompoundValue> {
152 match self {
153 Self::Compound(v) => Some(v),
154 _ => None,
155 }
156 }
157
158 pub fn as_boolean(&self) -> Option<bool> {
162 match self {
163 Self::Primitive(PrimitiveValue::Boolean(v)) => Some(*v),
164 _ => None,
165 }
166 }
167
168 pub fn unwrap_boolean(self) -> bool {
174 match self {
175 Self::Primitive(PrimitiveValue::Boolean(v)) => v,
176 _ => panic!("value is not a boolean"),
177 }
178 }
179
180 pub fn as_integer(&self) -> Option<i64> {
184 match self {
185 Self::Primitive(PrimitiveValue::Integer(v)) => Some(*v),
186 _ => None,
187 }
188 }
189
190 pub fn unwrap_integer(self) -> i64 {
196 match self {
197 Self::Primitive(PrimitiveValue::Integer(v)) => v,
198 _ => panic!("value is not an integer"),
199 }
200 }
201
202 pub fn as_float(&self) -> Option<f64> {
206 match self {
207 Self::Primitive(PrimitiveValue::Float(v)) => Some((*v).into()),
208 _ => None,
209 }
210 }
211
212 pub fn unwrap_float(self) -> f64 {
218 match self {
219 Self::Primitive(PrimitiveValue::Float(v)) => v.into(),
220 _ => panic!("value is not a float"),
221 }
222 }
223
224 pub fn as_string(&self) -> Option<&Arc<String>> {
228 match self {
229 Self::Primitive(PrimitiveValue::String(s)) => Some(s),
230 _ => None,
231 }
232 }
233
234 pub fn unwrap_string(self) -> Arc<String> {
240 match self {
241 Self::Primitive(PrimitiveValue::String(s)) => s,
242 _ => panic!("value is not a string"),
243 }
244 }
245
246 pub fn as_file(&self) -> Option<&Arc<String>> {
250 match self {
251 Self::Primitive(PrimitiveValue::File(s)) => Some(s),
252 _ => None,
253 }
254 }
255
256 pub fn unwrap_file(self) -> Arc<String> {
262 match self {
263 Self::Primitive(PrimitiveValue::File(s)) => s,
264 _ => panic!("value is not a file"),
265 }
266 }
267
268 pub fn as_directory(&self) -> Option<&Arc<String>> {
272 match self {
273 Self::Primitive(PrimitiveValue::Directory(s)) => Some(s),
274 _ => None,
275 }
276 }
277
278 pub fn unwrap_directory(self) -> Arc<String> {
284 match self {
285 Self::Primitive(PrimitiveValue::Directory(s)) => s,
286 _ => panic!("value is not a directory"),
287 }
288 }
289
290 pub fn as_pair(&self) -> Option<&Pair> {
294 match self {
295 Self::Compound(CompoundValue::Pair(v)) => Some(v),
296 _ => None,
297 }
298 }
299
300 pub fn unwrap_pair(self) -> Pair {
306 match self {
307 Self::Compound(CompoundValue::Pair(v)) => v,
308 _ => panic!("value is not a pair"),
309 }
310 }
311
312 pub fn as_array(&self) -> Option<&Array> {
316 match self {
317 Self::Compound(CompoundValue::Array(v)) => Some(v),
318 _ => None,
319 }
320 }
321
322 pub fn unwrap_array(self) -> Array {
328 match self {
329 Self::Compound(CompoundValue::Array(v)) => v,
330 _ => panic!("value is not an array"),
331 }
332 }
333
334 pub fn as_map(&self) -> Option<&Map> {
338 match self {
339 Self::Compound(CompoundValue::Map(v)) => Some(v),
340 _ => None,
341 }
342 }
343
344 pub fn unwrap_map(self) -> Map {
350 match self {
351 Self::Compound(CompoundValue::Map(v)) => v,
352 _ => panic!("value is not a map"),
353 }
354 }
355
356 pub fn as_object(&self) -> Option<&Object> {
360 match self {
361 Self::Compound(CompoundValue::Object(v)) => Some(v),
362 _ => None,
363 }
364 }
365
366 pub fn unwrap_object(self) -> Object {
372 match self {
373 Self::Compound(CompoundValue::Object(v)) => v,
374 _ => panic!("value is not an object"),
375 }
376 }
377
378 pub fn as_struct(&self) -> Option<&Struct> {
382 match self {
383 Self::Compound(CompoundValue::Struct(v)) => Some(v),
384 _ => None,
385 }
386 }
387
388 pub fn unwrap_struct(self) -> Struct {
394 match self {
395 Self::Compound(CompoundValue::Struct(v)) => v,
396 _ => panic!("value is not a struct"),
397 }
398 }
399
400 pub fn as_task(&self) -> Option<&TaskValue> {
404 match self {
405 Self::Task(v) => Some(v),
406 _ => None,
407 }
408 }
409
410 pub(crate) fn as_task_mut(&mut self) -> Option<&mut TaskValue> {
414 match self {
415 Self::Task(v) => Some(v),
416 _ => None,
417 }
418 }
419
420 pub fn unwrap_task(self) -> TaskValue {
426 match self {
427 Self::Task(v) => v,
428 _ => panic!("value is not a task"),
429 }
430 }
431
432 pub fn as_hints(&self) -> Option<&HintsValue> {
436 match self {
437 Self::Hints(v) => Some(v),
438 _ => None,
439 }
440 }
441
442 pub fn unwrap_hints(self) -> HintsValue {
448 match self {
449 Self::Hints(v) => v,
450 _ => panic!("value is not a hints value"),
451 }
452 }
453
454 pub fn as_call(&self) -> Option<&CallValue> {
458 match self {
459 Self::Call(v) => Some(v),
460 _ => None,
461 }
462 }
463
464 pub fn unwrap_call(self) -> CallValue {
470 match self {
471 Self::Call(v) => v,
472 _ => panic!("value is not a call value"),
473 }
474 }
475
476 pub(crate) fn visit_paths(
480 &self,
481 optional: bool,
482 cb: &mut impl FnMut(bool, &PrimitiveValue) -> Result<()>,
483 ) -> Result<()> {
484 match self {
485 Self::Primitive(v) => v.visit_paths(optional, cb),
486 Self::Compound(v) => v.visit_paths(cb),
487 _ => Ok(()),
488 }
489 }
490
491 pub(crate) fn visit_paths_mut(
498 &mut self,
499 optional: bool,
500 cb: &mut impl FnMut(bool, &mut PrimitiveValue) -> Result<bool>,
501 ) -> Result<()> {
502 match self {
503 Self::Primitive(v) => {
504 if !v.visit_paths_mut(optional, cb)? {
505 *self = Value::None;
506 }
507
508 Ok(())
509 }
510 Self::Compound(v) => v.visit_paths_mut(cb),
511 _ => Ok(()),
512 }
513 }
514
515 pub fn equals(left: &Self, right: &Self) -> Option<bool> {
520 match (left, right) {
521 (Value::None, Value::None) => Some(true),
522 (Value::None, _) | (_, Value::None) => Some(false),
523 (Value::Primitive(left), Value::Primitive(right)) => {
524 Some(PrimitiveValue::compare(left, right)? == Ordering::Equal)
525 }
526 (Value::Compound(left), Value::Compound(right)) => CompoundValue::equals(left, right),
527 _ => None,
528 }
529 }
530}
531
532impl fmt::Display for Value {
533 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
534 match self {
535 Self::None => write!(f, "None"),
536 Self::Primitive(v) => v.fmt(f),
537 Self::Compound(v) => v.fmt(f),
538 Self::Task(_) => write!(f, "task"),
539 Self::Hints(v) => v.fmt(f),
540 Self::Input(v) => v.fmt(f),
541 Self::Output(v) => v.fmt(f),
542 Self::Call(c) => c.fmt(f),
543 }
544 }
545}
546
547impl Coercible for Value {
548 fn coerce(&self, target: &Type) -> Result<Self> {
549 if target.is_union() || target.is_none() || self.ty().eq(target) {
550 return Ok(self.clone());
551 }
552
553 match self {
554 Self::None => {
555 if target.is_optional() {
556 Ok(Self::None)
557 } else {
558 bail!("cannot coerce `None` to non-optional type `{target}`");
559 }
560 }
561 Self::Primitive(v) => v.coerce(target).map(Self::Primitive),
562 Self::Compound(v) => v.coerce(target).map(Self::Compound),
563 Self::Task(_) => {
564 if matches!(target, Type::Task) {
565 return Ok(self.clone());
566 }
567
568 bail!("task variables cannot be coerced to any other type");
569 }
570 Self::Hints(_) => {
571 if matches!(target, Type::Hints) {
572 return Ok(self.clone());
573 }
574
575 bail!("hints values cannot be coerced to any other type");
576 }
577 Self::Input(_) => {
578 if matches!(target, Type::Input) {
579 return Ok(self.clone());
580 }
581
582 bail!("input values cannot be coerced to any other type");
583 }
584 Self::Output(_) => {
585 if matches!(target, Type::Output) {
586 return Ok(self.clone());
587 }
588
589 bail!("output values cannot be coerced to any other type");
590 }
591 Self::Call(_) => {
592 bail!("call values cannot be coerced to any other type");
593 }
594 }
595 }
596}
597
598impl From<bool> for Value {
599 fn from(value: bool) -> Self {
600 Self::Primitive(value.into())
601 }
602}
603
604impl From<i64> for Value {
605 fn from(value: i64) -> Self {
606 Self::Primitive(value.into())
607 }
608}
609
610impl TryFrom<u64> for Value {
611 type Error = std::num::TryFromIntError;
612
613 fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
614 let value: i64 = value.try_into()?;
615 Ok(value.into())
616 }
617}
618
619impl From<f64> for Value {
620 fn from(value: f64) -> Self {
621 Self::Primitive(value.into())
622 }
623}
624
625impl From<String> for Value {
626 fn from(value: String) -> Self {
627 Self::Primitive(value.into())
628 }
629}
630
631impl From<PrimitiveValue> for Value {
632 fn from(value: PrimitiveValue) -> Self {
633 Self::Primitive(value)
634 }
635}
636
637impl From<Option<PrimitiveValue>> for Value {
638 fn from(value: Option<PrimitiveValue>) -> Self {
639 match value {
640 Some(v) => v.into(),
641 None => Self::None,
642 }
643 }
644}
645
646impl From<CompoundValue> for Value {
647 fn from(value: CompoundValue) -> Self {
648 Self::Compound(value)
649 }
650}
651
652impl From<Pair> for Value {
653 fn from(value: Pair) -> Self {
654 Self::Compound(value.into())
655 }
656}
657
658impl From<Array> for Value {
659 fn from(value: Array) -> Self {
660 Self::Compound(value.into())
661 }
662}
663
664impl From<Map> for Value {
665 fn from(value: Map) -> Self {
666 Self::Compound(value.into())
667 }
668}
669
670impl From<Object> for Value {
671 fn from(value: Object) -> Self {
672 Self::Compound(value.into())
673 }
674}
675
676impl From<Struct> for Value {
677 fn from(value: Struct) -> Self {
678 Self::Compound(value.into())
679 }
680}
681
682impl From<TaskValue> for Value {
683 fn from(value: TaskValue) -> Self {
684 Self::Task(value)
685 }
686}
687
688impl From<HintsValue> for Value {
689 fn from(value: HintsValue) -> Self {
690 Self::Hints(value)
691 }
692}
693
694impl From<CallValue> for Value {
695 fn from(value: CallValue) -> Self {
696 Self::Call(value)
697 }
698}
699
700impl<'de> serde::Deserialize<'de> for Value {
701 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
702 where
703 D: serde::Deserializer<'de>,
704 {
705 use serde::Deserialize as _;
706
707 struct Deserialize;
709
710 impl<'de> serde::de::DeserializeSeed<'de> for Deserialize {
711 type Value = Value;
712
713 fn deserialize<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
714 where
715 D: serde::Deserializer<'de>,
716 {
717 deserializer.deserialize_any(Visitor)
718 }
719 }
720
721 struct Visitor;
723
724 impl<'de> serde::de::Visitor<'de> for Visitor {
725 type Value = Value;
726
727 fn visit_unit<E>(self) -> std::result::Result<Self::Value, E>
728 where
729 E: serde::de::Error,
730 {
731 Ok(Value::None)
732 }
733
734 fn visit_none<E>(self) -> std::result::Result<Self::Value, E>
735 where
736 E: serde::de::Error,
737 {
738 Ok(Value::None)
739 }
740
741 fn visit_some<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
742 where
743 D: serde::Deserializer<'de>,
744 {
745 Value::deserialize(deserializer)
746 }
747
748 fn visit_bool<E>(self, v: bool) -> std::result::Result<Self::Value, E>
749 where
750 E: serde::de::Error,
751 {
752 Ok(Value::Primitive(PrimitiveValue::Boolean(v)))
753 }
754
755 fn visit_i64<E>(self, v: i64) -> std::result::Result<Self::Value, E>
756 where
757 E: serde::de::Error,
758 {
759 Ok(Value::Primitive(PrimitiveValue::Integer(v)))
760 }
761
762 fn visit_u64<E>(self, v: u64) -> std::result::Result<Self::Value, E>
763 where
764 E: serde::de::Error,
765 {
766 Ok(Value::Primitive(PrimitiveValue::Integer(
767 v.try_into().map_err(|_| {
768 E::custom("integer not in range for a 64-bit signed integer")
769 })?,
770 )))
771 }
772
773 fn visit_f64<E>(self, v: f64) -> std::result::Result<Self::Value, E>
774 where
775 E: serde::de::Error,
776 {
777 Ok(Value::Primitive(PrimitiveValue::Float(v.into())))
778 }
779
780 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
781 where
782 E: serde::de::Error,
783 {
784 Ok(Value::Primitive(PrimitiveValue::new_string(v)))
785 }
786
787 fn visit_string<E>(self, v: String) -> std::result::Result<Self::Value, E>
788 where
789 E: serde::de::Error,
790 {
791 Ok(Value::Primitive(PrimitiveValue::new_string(v)))
792 }
793
794 fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
795 where
796 A: serde::de::SeqAccess<'de>,
797 {
798 use serde::de::Error;
799
800 let mut elements = Vec::new();
801 while let Some(v) = seq.next_element_seed(Deserialize)? {
802 elements.push(v);
803 }
804
805 let element_ty = elements
806 .iter()
807 .try_fold(None, |mut ty, element| {
808 let element_ty = element.ty();
809 let ty = ty.get_or_insert(element_ty.clone());
810 ty.common_type(&element_ty).map(Some).ok_or_else(|| {
811 A::Error::custom(format!(
812 "a common element type does not exist between `{ty}` and \
813 `{element_ty}`"
814 ))
815 })
816 })?
817 .unwrap_or(Type::Union);
818
819 let ty: Type = ArrayType::new(element_ty).into();
820 Ok(Array::new(ty.clone(), elements)
821 .map_err(|e| A::Error::custom(format!("cannot coerce value to `{ty}`: {e:#}")))?
822 .into())
823 }
824
825 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
826 where
827 A: serde::de::MapAccess<'de>,
828 {
829 use serde::de::Error;
830
831 let mut members = IndexMap::new();
832 while let Some(key) = map.next_key::<String>()? {
833 if !is_ident(&key) {
834 return Err(A::Error::custom(format!(
835 "object key `{key}` is not a valid WDL identifier"
836 )));
837 }
838
839 members.insert(key, map.next_value_seed(Deserialize)?);
840 }
841
842 Ok(Value::Compound(CompoundValue::Object(Object::new(members))))
843 }
844
845 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
846 write!(f, "a WDL value")
847 }
848 }
849
850 deserializer.deserialize_any(Visitor)
851 }
852}
853
854#[derive(Debug, Clone)]
858pub enum PrimitiveValue {
859 Boolean(bool),
861 Integer(i64),
863 Float(OrderedFloat<f64>),
865 String(Arc<String>),
867 File(Arc<String>),
869 Directory(Arc<String>),
871}
872
873impl PrimitiveValue {
874 pub fn new_string(s: impl Into<String>) -> Self {
876 Self::String(Arc::new(s.into()))
877 }
878
879 pub fn new_file(s: impl Into<String>) -> Self {
881 Self::File(Arc::new(s.into()))
882 }
883
884 pub fn new_directory(s: impl Into<String>) -> Self {
886 Self::Directory(Arc::new(s.into()))
887 }
888
889 pub fn ty(&self) -> Type {
891 match self {
892 Self::Boolean(_) => PrimitiveType::Boolean.into(),
893 Self::Integer(_) => PrimitiveType::Integer.into(),
894 Self::Float(_) => PrimitiveType::Float.into(),
895 Self::String(_) => PrimitiveType::String.into(),
896 Self::File(_) => PrimitiveType::File.into(),
897 Self::Directory(_) => PrimitiveType::Directory.into(),
898 }
899 }
900
901 pub fn as_boolean(&self) -> Option<bool> {
905 match self {
906 Self::Boolean(v) => Some(*v),
907 _ => None,
908 }
909 }
910
911 pub fn unwrap_boolean(self) -> bool {
917 match self {
918 Self::Boolean(v) => v,
919 _ => panic!("value is not a boolean"),
920 }
921 }
922
923 pub fn as_integer(&self) -> Option<i64> {
927 match self {
928 Self::Integer(v) => Some(*v),
929 _ => None,
930 }
931 }
932
933 pub fn unwrap_integer(self) -> i64 {
939 match self {
940 Self::Integer(v) => v,
941 _ => panic!("value is not an integer"),
942 }
943 }
944
945 pub fn as_float(&self) -> Option<f64> {
949 match self {
950 Self::Float(v) => Some((*v).into()),
951 _ => None,
952 }
953 }
954
955 pub fn unwrap_float(self) -> f64 {
961 match self {
962 Self::Float(v) => v.into(),
963 _ => panic!("value is not a float"),
964 }
965 }
966
967 pub fn as_string(&self) -> Option<&Arc<String>> {
971 match self {
972 Self::String(s) => Some(s),
973 _ => None,
974 }
975 }
976
977 pub fn unwrap_string(self) -> Arc<String> {
983 match self {
984 Self::String(s) => s,
985 _ => panic!("value is not a string"),
986 }
987 }
988
989 pub fn as_file(&self) -> Option<&Arc<String>> {
993 match self {
994 Self::File(s) => Some(s),
995 _ => None,
996 }
997 }
998
999 pub fn unwrap_file(self) -> Arc<String> {
1005 match self {
1006 Self::File(s) => s,
1007 _ => panic!("value is not a file"),
1008 }
1009 }
1010
1011 pub fn as_directory(&self) -> Option<&Arc<String>> {
1015 match self {
1016 Self::Directory(s) => Some(s),
1017 _ => None,
1018 }
1019 }
1020
1021 pub fn unwrap_directory(self) -> Arc<String> {
1027 match self {
1028 Self::Directory(s) => s,
1029 _ => panic!("value is not a directory"),
1030 }
1031 }
1032
1033 pub fn compare(left: &Self, right: &Self) -> Option<Ordering> {
1040 match (left, right) {
1041 (Self::Boolean(left), Self::Boolean(right)) => Some(left.cmp(right)),
1042 (Self::Integer(left), Self::Integer(right)) => Some(left.cmp(right)),
1043 (Self::Integer(left), Self::Float(right)) => {
1044 Some(OrderedFloat(*left as f64).cmp(right))
1045 }
1046 (Self::Float(left), Self::Integer(right)) => {
1047 Some(left.cmp(&OrderedFloat(*right as f64)))
1048 }
1049 (Self::Float(left), Self::Float(right)) => Some(left.cmp(right)),
1050 (Self::String(left), Self::String(right))
1051 | (Self::String(left), Self::File(right))
1052 | (Self::String(left), Self::Directory(right))
1053 | (Self::File(left), Self::File(right))
1054 | (Self::File(left), Self::String(right))
1055 | (Self::Directory(left), Self::Directory(right))
1056 | (Self::Directory(left), Self::String(right)) => Some(left.cmp(right)),
1057 _ => None,
1058 }
1059 }
1060
1061 pub fn raw<'a>(
1068 &'a self,
1069 context: Option<&'a dyn EvaluationContext>,
1070 ) -> impl fmt::Display + use<'a> {
1071 struct Display<'a> {
1073 context: Option<&'a dyn EvaluationContext>,
1075 value: &'a PrimitiveValue,
1077 }
1078
1079 impl fmt::Display for Display<'_> {
1080 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1081 match self.value {
1082 PrimitiveValue::Boolean(v) => write!(f, "{v}"),
1083 PrimitiveValue::Integer(v) => write!(f, "{v}"),
1084 PrimitiveValue::Float(v) => write!(f, "{v:.6?}"),
1085 PrimitiveValue::String(v)
1086 | PrimitiveValue::File(v)
1087 | PrimitiveValue::Directory(v) => {
1088 match self.context.and_then(|c| c.translate_path(v)) {
1089 Some(path) => write!(f, "{path}", path = path.display()),
1090 None => {
1091 write!(f, "{v}")
1092 }
1093 }
1094 }
1095 }
1096 }
1097 }
1098
1099 Display {
1100 context,
1101 value: self,
1102 }
1103 }
1104
1105 fn visit_paths(
1109 &self,
1110 optional: bool,
1111 cb: &mut impl FnMut(bool, &PrimitiveValue) -> Result<()>,
1112 ) -> Result<()> {
1113 match self {
1114 Self::File(_) | Self::Directory(_) => cb(optional, self),
1115 _ => Ok(()),
1116 }
1117 }
1118
1119 fn visit_paths_mut(
1126 &mut self,
1127 optional: bool,
1128 cb: &mut impl FnMut(bool, &mut PrimitiveValue) -> Result<bool>,
1129 ) -> Result<bool> {
1130 match self {
1131 Self::File(_) | Self::Directory(_) => cb(optional, self),
1132 _ => Ok(true),
1133 }
1134 }
1135
1136 pub(crate) fn expand_path(&mut self) -> Result<()> {
1138 let path = match self {
1139 PrimitiveValue::File(path) => path,
1140 PrimitiveValue::Directory(path) => path,
1141 _ => unreachable!("only file and directory values can be expanded"),
1142 };
1143
1144 let result = shellexpand::full(path.as_str())
1145 .context("expanding file/directory path using shell rules")?;
1146 *Arc::make_mut(path) = result.to_string();
1147
1148 Ok(())
1149 }
1150
1151 pub(crate) fn join_path_to(&mut self, to: &Path) {
1157 let path = match self {
1158 PrimitiveValue::File(path) => path,
1159 PrimitiveValue::Directory(path) => path,
1160 _ => unreachable!("only file and directory values can be joined to a path"),
1161 };
1162
1163 if path::is_url(path) {
1165 return;
1166 }
1167
1168 if let Ok(s) = to
1170 .join(path.as_str())
1171 .clean()
1172 .into_os_string()
1173 .into_string()
1174 {
1175 *Arc::make_mut(path) = s;
1176 }
1177 }
1178
1179 pub(crate) fn ensure_path_exists(&self, optional: bool) -> Result<bool> {
1192 let (path, is_file) = match self {
1193 PrimitiveValue::File(path) => (path, true),
1194 PrimitiveValue::Directory(path) => (path, false),
1195 _ => unreachable!("only file and directory values should be passed to the callback"),
1196 };
1197
1198 if path::is_file_url(path) {
1200 let exists = path::parse_url(path)
1201 .and_then(|url| url.to_file_path().ok())
1202 .map(|p| p.exists())
1203 .unwrap_or(false);
1204 if exists {
1205 return Ok(true);
1206 }
1207
1208 if optional && !exists {
1209 return Ok(false);
1210 }
1211
1212 bail!("path `{path}` does not exist");
1213 } else if path::is_url(path) {
1214 return Ok(true);
1216 }
1217
1218 let path = Path::new(path.as_str());
1220 if is_file && !path.is_file() {
1221 if optional {
1222 return Ok(false);
1223 }
1224
1225 bail!("file `{path}` does not exist", path = path.display());
1226 } else if !is_file && !path.is_dir() {
1227 if optional {
1228 return Ok(false);
1229 }
1230
1231 bail!("directory `{path}` does not exist", path = path.display())
1232 }
1233
1234 Ok(true)
1235 }
1236}
1237
1238impl fmt::Display for PrimitiveValue {
1239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1240 match self {
1241 Self::Boolean(v) => write!(f, "{v}"),
1242 Self::Integer(v) => write!(f, "{v}"),
1243 Self::Float(v) => write!(f, "{v:.6?}"),
1244 Self::String(s) | Self::File(s) | Self::Directory(s) => {
1245 write!(f, "\"{s}\"")
1247 }
1248 }
1249 }
1250}
1251
1252impl PartialEq for PrimitiveValue {
1253 fn eq(&self, other: &Self) -> bool {
1254 Self::compare(self, other) == Some(Ordering::Equal)
1255 }
1256}
1257
1258impl Eq for PrimitiveValue {}
1259
1260impl Hash for PrimitiveValue {
1261 fn hash<H: Hasher>(&self, state: &mut H) {
1262 match self {
1263 Self::Boolean(v) => {
1264 0.hash(state);
1265 v.hash(state);
1266 }
1267 Self::Integer(v) => {
1268 1.hash(state);
1269 v.hash(state);
1270 }
1271 Self::Float(v) => {
1272 1.hash(state);
1275 v.hash(state);
1276 }
1277 Self::String(v) | Self::File(v) | Self::Directory(v) => {
1278 2.hash(state);
1281 v.hash(state);
1282 }
1283 }
1284 }
1285}
1286
1287impl From<bool> for PrimitiveValue {
1288 fn from(value: bool) -> Self {
1289 Self::Boolean(value)
1290 }
1291}
1292
1293impl From<i64> for PrimitiveValue {
1294 fn from(value: i64) -> Self {
1295 Self::Integer(value)
1296 }
1297}
1298
1299impl From<f64> for PrimitiveValue {
1300 fn from(value: f64) -> Self {
1301 Self::Float(value.into())
1302 }
1303}
1304
1305impl From<String> for PrimitiveValue {
1306 fn from(value: String) -> Self {
1307 Self::String(value.into())
1308 }
1309}
1310
1311impl Coercible for PrimitiveValue {
1312 fn coerce(&self, target: &Type) -> Result<Self> {
1313 if target.is_union() || target.is_none() || self.ty().eq(target) {
1314 return Ok(self.clone());
1315 }
1316
1317 match self {
1318 Self::Boolean(v) => {
1319 target
1320 .as_primitive()
1321 .and_then(|ty| match ty {
1322 PrimitiveType::Boolean => Some(Self::Boolean(*v)),
1324 _ => None,
1325 })
1326 .with_context(|| format!("cannot coerce type `Boolean` to type `{target}`"))
1327 }
1328 Self::Integer(v) => {
1329 target
1330 .as_primitive()
1331 .and_then(|ty| match ty {
1332 PrimitiveType::Integer => Some(Self::Integer(*v)),
1334 PrimitiveType::Float => Some(Self::Float((*v as f64).into())),
1336 _ => None,
1337 })
1338 .with_context(|| format!("cannot coerce type `Int` to type `{target}`"))
1339 }
1340 Self::Float(v) => {
1341 target
1342 .as_primitive()
1343 .and_then(|ty| match ty {
1344 PrimitiveType::Float => Some(Self::Float(*v)),
1346 _ => None,
1347 })
1348 .with_context(|| format!("cannot coerce type `Float` to type `{target}`"))
1349 }
1350 Self::String(s) => {
1351 target
1352 .as_primitive()
1353 .and_then(|ty| match ty {
1354 PrimitiveType::String => Some(Self::String(s.clone())),
1356 PrimitiveType::File => Some(Self::File(s.clone())),
1358 PrimitiveType::Directory => Some(Self::Directory(s.clone())),
1360 _ => None,
1361 })
1362 .with_context(|| format!("cannot coerce type `String` to type `{target}`"))
1363 }
1364 Self::File(s) => {
1365 target
1366 .as_primitive()
1367 .and_then(|ty| match ty {
1368 PrimitiveType::File => Some(Self::File(s.clone())),
1370 PrimitiveType::String => Some(Self::String(s.clone())),
1372 _ => None,
1373 })
1374 .with_context(|| format!("cannot coerce type `File` to type `{target}`"))
1375 }
1376 Self::Directory(s) => {
1377 target
1378 .as_primitive()
1379 .and_then(|ty| match ty {
1380 PrimitiveType::Directory => Some(Self::Directory(s.clone())),
1382 PrimitiveType::String => Some(Self::String(s.clone())),
1384 _ => None,
1385 })
1386 .with_context(|| format!("cannot coerce type `Directory` to type `{target}`"))
1387 }
1388 }
1389 }
1390}
1391
1392impl serde::Serialize for PrimitiveValue {
1393 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1394 where
1395 S: serde::Serializer,
1396 {
1397 match self {
1398 Self::Boolean(v) => v.serialize(serializer),
1399 Self::Integer(v) => v.serialize(serializer),
1400 Self::Float(v) => v.serialize(serializer),
1401 Self::String(s) | Self::File(s) | Self::Directory(s) => s.serialize(serializer),
1402 }
1403 }
1404}
1405
1406#[derive(Debug, Clone)]
1410pub struct Pair {
1411 ty: Type,
1413 values: Arc<(Value, Value)>,
1415}
1416
1417impl Pair {
1418 pub fn new(
1427 ty: impl Into<Type>,
1428 left: impl Into<Value>,
1429 right: impl Into<Value>,
1430 ) -> Result<Self> {
1431 let ty = ty.into();
1432 if let Type::Compound(CompoundType::Pair(ty), _) = ty {
1433 let left = left
1434 .into()
1435 .coerce(ty.left_type())
1436 .context("failed to coerce pair's left value")?;
1437 let right = right
1438 .into()
1439 .coerce(ty.right_type())
1440 .context("failed to coerce pair's right value")?;
1441 return Ok(Self::new_unchecked(
1442 Type::Compound(CompoundType::Pair(ty), false),
1443 left,
1444 right,
1445 ));
1446 }
1447
1448 panic!("type `{ty}` is not a pair type");
1449 }
1450
1451 pub(crate) fn new_unchecked(ty: Type, left: Value, right: Value) -> Self {
1454 assert!(ty.as_pair().is_some());
1455 Self {
1456 ty: ty.require(),
1457 values: Arc::new((left, right)),
1458 }
1459 }
1460
1461 pub fn ty(&self) -> Type {
1463 self.ty.clone()
1464 }
1465
1466 pub fn left(&self) -> &Value {
1468 &self.values.0
1469 }
1470
1471 pub fn right(&self) -> &Value {
1473 &self.values.1
1474 }
1475}
1476
1477impl fmt::Display for Pair {
1478 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1479 write!(
1480 f,
1481 "({left}, {right})",
1482 left = self.values.0,
1483 right = self.values.1
1484 )
1485 }
1486}
1487
1488#[derive(Debug, Clone)]
1492pub struct Array {
1493 ty: Type,
1495 elements: Option<Arc<Vec<Value>>>,
1499}
1500
1501impl Array {
1502 pub fn new<V>(ty: impl Into<Type>, elements: impl IntoIterator<Item = V>) -> Result<Self>
1511 where
1512 V: Into<Value>,
1513 {
1514 let ty = ty.into();
1515 if let Type::Compound(CompoundType::Array(ty), _) = ty {
1516 let element_type = ty.element_type();
1517 let elements = elements
1518 .into_iter()
1519 .enumerate()
1520 .map(|(i, v)| {
1521 let v = v.into();
1522 v.coerce(element_type)
1523 .with_context(|| format!("failed to coerce array element at index {i}"))
1524 })
1525 .collect::<Result<Vec<_>>>()?;
1526
1527 return Ok(Self::new_unchecked(
1528 Type::Compound(CompoundType::Array(ty.unqualified()), false),
1529 elements,
1530 ));
1531 }
1532
1533 panic!("type `{ty}` is not an array type");
1534 }
1535
1536 pub(crate) fn new_unchecked(ty: Type, elements: Vec<Value>) -> Self {
1539 let ty = if let Type::Compound(CompoundType::Array(ty), _) = ty {
1540 Type::Compound(CompoundType::Array(ty.unqualified()), false)
1541 } else {
1542 panic!("type is not an array type");
1543 };
1544
1545 Self {
1546 ty,
1547 elements: if elements.is_empty() {
1548 None
1549 } else {
1550 Some(Arc::new(elements))
1551 },
1552 }
1553 }
1554
1555 pub fn ty(&self) -> Type {
1557 self.ty.clone()
1558 }
1559
1560 pub fn as_slice(&self) -> &[Value] {
1562 self.elements.as_ref().map(|v| v.as_slice()).unwrap_or(&[])
1563 }
1564
1565 pub fn len(&self) -> usize {
1567 self.elements.as_ref().map(|v| v.len()).unwrap_or(0)
1568 }
1569
1570 pub fn is_empty(&self) -> bool {
1572 self.len() == 0
1573 }
1574}
1575
1576impl fmt::Display for Array {
1577 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1578 write!(f, "[")?;
1579
1580 if let Some(elements) = &self.elements {
1581 for (i, element) in elements.iter().enumerate() {
1582 if i > 0 {
1583 write!(f, ", ")?;
1584 }
1585
1586 write!(f, "{element}")?;
1587 }
1588 }
1589
1590 write!(f, "]")
1591 }
1592}
1593
1594#[derive(Debug, Clone)]
1598pub struct Map {
1599 ty: Type,
1601 elements: Option<Arc<IndexMap<Option<PrimitiveValue>, Value>>>,
1605}
1606
1607impl Map {
1608 pub fn new<K, V>(
1617 ty: impl Into<Type>,
1618 elements: impl IntoIterator<Item = (K, V)>,
1619 ) -> Result<Self>
1620 where
1621 K: Into<Value>,
1622 V: Into<Value>,
1623 {
1624 let ty = ty.into();
1625 if let Type::Compound(CompoundType::Map(ty), _) = ty {
1626 let key_type = ty.key_type();
1627 let value_type = ty.value_type();
1628
1629 let elements = elements
1630 .into_iter()
1631 .enumerate()
1632 .map(|(i, (k, v))| {
1633 let k = k.into();
1634 let v = v.into();
1635 Ok((
1636 if k.is_none() {
1637 None
1638 } else {
1639 match k.coerce(key_type).with_context(|| {
1640 format!("failed to coerce map key for element at index {i}")
1641 })? {
1642 Value::None => None,
1643 Value::Primitive(v) => Some(v),
1644 _ => {
1645 bail!("not all key values are primitive")
1646 }
1647 }
1648 },
1649 v.coerce(value_type).with_context(|| {
1650 format!("failed to coerce map value for element at index {i}")
1651 })?,
1652 ))
1653 })
1654 .collect::<Result<_>>()?;
1655
1656 return Ok(Self::new_unchecked(
1657 Type::Compound(CompoundType::Map(ty), false),
1658 elements,
1659 ));
1660 }
1661
1662 panic!("type `{ty}` is not a map type");
1663 }
1664
1665 pub(crate) fn new_unchecked(
1668 ty: Type,
1669 elements: IndexMap<Option<PrimitiveValue>, Value>,
1670 ) -> Self {
1671 assert!(ty.as_map().is_some());
1672 Self {
1673 ty: ty.require(),
1674 elements: if elements.is_empty() {
1675 None
1676 } else {
1677 Some(Arc::new(elements))
1678 },
1679 }
1680 }
1681
1682 pub fn ty(&self) -> Type {
1684 self.ty.clone()
1685 }
1686
1687 pub fn iter(&self) -> impl Iterator<Item = (&Option<PrimitiveValue>, &Value)> {
1689 self.elements
1690 .as_ref()
1691 .map(|m| Either::Left(m.iter()))
1692 .unwrap_or(Either::Right(std::iter::empty()))
1693 }
1694
1695 pub fn keys(&self) -> impl Iterator<Item = &Option<PrimitiveValue>> {
1697 self.elements
1698 .as_ref()
1699 .map(|m| Either::Left(m.keys()))
1700 .unwrap_or(Either::Right(std::iter::empty()))
1701 }
1702
1703 pub fn values(&self) -> impl Iterator<Item = &Value> {
1705 self.elements
1706 .as_ref()
1707 .map(|m| Either::Left(m.values()))
1708 .unwrap_or(Either::Right(std::iter::empty()))
1709 }
1710
1711 pub fn contains_key(&self, key: &Option<PrimitiveValue>) -> bool {
1713 self.elements
1714 .as_ref()
1715 .map(|m| m.contains_key(key))
1716 .unwrap_or(false)
1717 }
1718
1719 pub fn get(&self, key: &Option<PrimitiveValue>) -> Option<&Value> {
1721 self.elements.as_ref().and_then(|m| m.get(key))
1722 }
1723
1724 pub fn len(&self) -> usize {
1726 self.elements.as_ref().map(|m| m.len()).unwrap_or(0)
1727 }
1728
1729 pub fn is_empty(&self) -> bool {
1731 self.len() == 0
1732 }
1733}
1734
1735impl fmt::Display for Map {
1736 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1737 write!(f, "{{")?;
1738
1739 for (i, (k, v)) in self.iter().enumerate() {
1740 if i > 0 {
1741 write!(f, ", ")?;
1742 }
1743
1744 match k {
1745 Some(k) => write!(f, "{k}: {v}")?,
1746 None => write!(f, "None: {v}")?,
1747 }
1748 }
1749
1750 write!(f, "}}")
1751 }
1752}
1753
1754#[derive(Debug, Clone)]
1758pub struct Object {
1759 pub(crate) members: Option<Arc<IndexMap<String, Value>>>,
1763}
1764
1765impl Object {
1766 pub(crate) fn new(members: IndexMap<String, Value>) -> Self {
1770 Self {
1771 members: if members.is_empty() {
1772 None
1773 } else {
1774 Some(Arc::new(members))
1775 },
1776 }
1777 }
1778
1779 pub fn empty() -> Self {
1781 Self::new(IndexMap::default())
1782 }
1783
1784 pub fn from_v1_metadata<N: TreeNode>(
1786 items: impl Iterator<Item = v1::MetadataObjectItem<N>>,
1787 ) -> Self {
1788 Object::new(
1789 items
1790 .map(|i| {
1791 (
1792 i.name().text().to_string(),
1793 Value::from_v1_metadata(&i.value()),
1794 )
1795 })
1796 .collect::<IndexMap<_, _>>(),
1797 )
1798 }
1799
1800 pub fn ty(&self) -> Type {
1802 Type::Object
1803 }
1804
1805 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
1807 self.members
1808 .as_ref()
1809 .map(|m| Either::Left(m.iter().map(|(k, v)| (k.as_str(), v))))
1810 .unwrap_or(Either::Right(std::iter::empty()))
1811 }
1812
1813 pub fn keys(&self) -> impl Iterator<Item = &str> {
1815 self.members
1816 .as_ref()
1817 .map(|m| Either::Left(m.keys().map(|k| k.as_str())))
1818 .unwrap_or(Either::Right(std::iter::empty()))
1819 }
1820
1821 pub fn values(&self) -> impl Iterator<Item = &Value> {
1823 self.members
1824 .as_ref()
1825 .map(|m| Either::Left(m.values()))
1826 .unwrap_or(Either::Right(std::iter::empty()))
1827 }
1828
1829 pub fn contains_key(&self, key: &str) -> bool {
1831 self.members
1832 .as_ref()
1833 .map(|m| m.contains_key(key))
1834 .unwrap_or(false)
1835 }
1836
1837 pub fn get(&self, key: &str) -> Option<&Value> {
1839 self.members.as_ref().and_then(|m| m.get(key))
1840 }
1841
1842 pub fn len(&self) -> usize {
1844 self.members.as_ref().map(|m| m.len()).unwrap_or(0)
1845 }
1846
1847 pub fn is_empty(&self) -> bool {
1849 self.len() == 0
1850 }
1851}
1852
1853impl fmt::Display for Object {
1854 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1855 write!(f, "object {{")?;
1856
1857 for (i, (k, v)) in self.iter().enumerate() {
1858 if i > 0 {
1859 write!(f, ", ")?;
1860 }
1861
1862 write!(f, "{k}: {v}")?;
1863 }
1864
1865 write!(f, "}}")
1866 }
1867}
1868
1869#[derive(Debug, Clone)]
1873pub struct Struct {
1874 ty: Type,
1876 name: Arc<String>,
1878 pub(crate) members: Arc<IndexMap<String, Value>>,
1880}
1881
1882impl Struct {
1883 pub fn new<S, V>(ty: impl Into<Type>, members: impl IntoIterator<Item = (S, V)>) -> Result<Self>
1892 where
1893 S: Into<String>,
1894 V: Into<Value>,
1895 {
1896 let ty = ty.into();
1897 if let Type::Compound(CompoundType::Struct(ty), optional) = ty {
1898 let mut members = members
1899 .into_iter()
1900 .map(|(n, v)| {
1901 let n = n.into();
1902 let v = v.into();
1903 let v = v
1904 .coerce(ty.members().get(&n).ok_or_else(|| {
1905 anyhow!("struct does not contain a member named `{n}`")
1906 })?)
1907 .with_context(|| format!("failed to coerce struct member `{n}`"))?;
1908 Ok((n, v))
1909 })
1910 .collect::<Result<IndexMap<_, _>>>()?;
1911
1912 for (name, ty) in ty.members().iter() {
1913 if ty.is_optional() {
1915 if !members.contains_key(name) {
1916 members.insert(name.clone(), Value::None);
1917 }
1918 } else {
1919 if !members.contains_key(name) {
1921 bail!("missing a value for struct member `{name}`");
1922 }
1923 }
1924 }
1925
1926 let name = ty.name().to_string();
1927 return Ok(Self {
1928 ty: Type::Compound(CompoundType::Struct(ty), optional),
1929 name: Arc::new(name),
1930 members: Arc::new(members),
1931 });
1932 }
1933
1934 panic!("type `{ty}` is not a struct type");
1935 }
1936
1937 pub(crate) fn new_unchecked(
1940 ty: Type,
1941 name: Arc<String>,
1942 members: Arc<IndexMap<String, Value>>,
1943 ) -> Self {
1944 assert!(ty.as_struct().is_some());
1945 Self {
1946 ty: ty.require(),
1947 name,
1948 members,
1949 }
1950 }
1951
1952 pub fn ty(&self) -> Type {
1954 self.ty.clone()
1955 }
1956
1957 pub fn name(&self) -> &Arc<String> {
1959 &self.name
1960 }
1961
1962 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
1964 self.members.iter().map(|(k, v)| (k.as_str(), v))
1965 }
1966
1967 pub fn keys(&self) -> impl Iterator<Item = &str> {
1969 self.members.keys().map(|k| k.as_str())
1970 }
1971
1972 pub fn values(&self) -> impl Iterator<Item = &Value> {
1974 self.members.values()
1975 }
1976
1977 pub fn contains_key(&self, key: &str) -> bool {
1979 self.members.contains_key(key)
1980 }
1981
1982 pub fn get(&self, key: &str) -> Option<&Value> {
1984 self.members.get(key)
1985 }
1986}
1987
1988impl fmt::Display for Struct {
1989 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1990 write!(f, "{name} {{", name = self.name)?;
1991
1992 for (i, (k, v)) in self.members.iter().enumerate() {
1993 if i > 0 {
1994 write!(f, ", ")?;
1995 }
1996
1997 write!(f, "{k}: {v}")?;
1998 }
1999
2000 write!(f, "}}")
2001 }
2002}
2003
2004#[derive(Debug, Clone)]
2008pub enum CompoundValue {
2009 Pair(Pair),
2011 Array(Array),
2013 Map(Map),
2015 Object(Object),
2017 Struct(Struct),
2019}
2020
2021impl CompoundValue {
2022 pub fn ty(&self) -> Type {
2024 match self {
2025 CompoundValue::Pair(v) => v.ty(),
2026 CompoundValue::Array(v) => v.ty(),
2027 CompoundValue::Map(v) => v.ty(),
2028 CompoundValue::Object(v) => v.ty(),
2029 CompoundValue::Struct(v) => v.ty(),
2030 }
2031 }
2032
2033 pub fn as_pair(&self) -> Option<&Pair> {
2037 match self {
2038 Self::Pair(v) => Some(v),
2039 _ => None,
2040 }
2041 }
2042
2043 pub fn unwrap_pair(self) -> Pair {
2049 match self {
2050 Self::Pair(v) => v,
2051 _ => panic!("value is not a pair"),
2052 }
2053 }
2054
2055 pub fn as_array(&self) -> Option<&Array> {
2059 match self {
2060 Self::Array(v) => Some(v),
2061 _ => None,
2062 }
2063 }
2064
2065 pub fn unwrap_array(self) -> Array {
2071 match self {
2072 Self::Array(v) => v,
2073 _ => panic!("value is not an array"),
2074 }
2075 }
2076
2077 pub fn as_map(&self) -> Option<&Map> {
2081 match self {
2082 Self::Map(v) => Some(v),
2083 _ => None,
2084 }
2085 }
2086
2087 pub fn unwrap_map(self) -> Map {
2093 match self {
2094 Self::Map(v) => v,
2095 _ => panic!("value is not a map"),
2096 }
2097 }
2098
2099 pub fn as_object(&self) -> Option<&Object> {
2103 match self {
2104 Self::Object(v) => Some(v),
2105 _ => None,
2106 }
2107 }
2108
2109 pub fn unwrap_object(self) -> Object {
2115 match self {
2116 Self::Object(v) => v,
2117 _ => panic!("value is not an object"),
2118 }
2119 }
2120
2121 pub fn as_struct(&self) -> Option<&Struct> {
2125 match self {
2126 Self::Struct(v) => Some(v),
2127 _ => None,
2128 }
2129 }
2130
2131 pub fn unwrap_struct(self) -> Struct {
2137 match self {
2138 Self::Struct(v) => v,
2139 _ => panic!("value is not a struct"),
2140 }
2141 }
2142
2143 pub fn equals(left: &Self, right: &Self) -> Option<bool> {
2149 if left.ty() != right.ty() {
2152 return None;
2153 }
2154
2155 match (left, right) {
2156 (Self::Pair(left), Self::Pair(right)) => Some(
2157 Value::equals(left.left(), right.left())?
2158 && Value::equals(left.right(), right.right())?,
2159 ),
2160 (CompoundValue::Array(left), CompoundValue::Array(right)) => Some(
2161 left.len() == right.len()
2162 && left
2163 .as_slice()
2164 .iter()
2165 .zip(right.as_slice())
2166 .all(|(l, r)| Value::equals(l, r).unwrap_or(false)),
2167 ),
2168 (CompoundValue::Map(left), CompoundValue::Map(right)) => Some(
2169 left.len() == right.len()
2170 && left.iter().zip(right.iter()).all(|((lk, lv), (rk, rv))| {
2172 match (lk, rk) {
2173 (None, None) => {},
2174 (Some(lk), Some(rk)) if lk == rk => {},
2175 _ => return false
2176 }
2177
2178 Value::equals(lv, rv).unwrap_or(false)
2179 }),
2180 ),
2181 (CompoundValue::Object(left), CompoundValue::Object(right)) => Some(
2182 left.len() == right.len()
2183 && left.iter().all(|(k, left)| match right.get(k) {
2184 Some(right) => Value::equals(left, right).unwrap_or(false),
2185 None => false,
2186 }),
2187 ),
2188 (
2189 CompoundValue::Struct(Struct { members: left, .. }),
2190 CompoundValue::Struct(Struct { members: right, .. }),
2191 ) => Some(
2192 left.len() == right.len()
2193 && left.iter().all(|(k, left)| match right.get(k) {
2194 Some(right) => Value::equals(left, right).unwrap_or(false),
2195 None => false,
2196 }),
2197 ),
2198 _ => None,
2199 }
2200 }
2201
2202 fn visit_paths(&self, cb: &mut impl FnMut(bool, &PrimitiveValue) -> Result<()>) -> Result<()> {
2206 match self {
2207 Self::Pair(pair) => {
2208 let ty = pair.ty.as_pair().expect("should be a pair type");
2209 pair.left().visit_paths(ty.left_type().is_optional(), cb)?;
2210 pair.right()
2211 .visit_paths(ty.right_type().is_optional(), cb)?;
2212 }
2213 Self::Array(array) => {
2214 let ty = array.ty.as_array().expect("should be an array type");
2215 let optional = ty.element_type().is_optional();
2216 if let Some(elements) = &array.elements {
2217 for v in elements.iter() {
2218 v.visit_paths(optional, cb)?;
2219 }
2220 }
2221 }
2222 Self::Map(map) => {
2223 let ty = map.ty.as_map().expect("should be a map type");
2224 let (key_optional, value_optional) =
2225 (ty.key_type().is_optional(), ty.value_type().is_optional());
2226 if let Some(elements) = &map.elements {
2227 for (k, v) in elements.iter() {
2228 if let Some(k) = k {
2229 k.visit_paths(key_optional, cb)?;
2230 }
2231
2232 v.visit_paths(value_optional, cb)?;
2233 }
2234 }
2235 }
2236 Self::Object(object) => {
2237 if let Some(members) = &object.members {
2238 for v in members.values() {
2239 v.visit_paths(false, cb)?;
2240 }
2241 }
2242 }
2243 Self::Struct(s) => {
2244 let ty = s.ty.as_struct().expect("should be a struct type");
2245 for (n, v) in s.members.iter() {
2246 v.visit_paths(ty.members()[n].is_optional(), cb)?;
2247 }
2248 }
2249 }
2250
2251 Ok(())
2252 }
2253
2254 fn visit_paths_mut(
2261 &mut self,
2262 cb: &mut impl FnMut(bool, &mut PrimitiveValue) -> Result<bool>,
2263 ) -> Result<()> {
2264 match self {
2265 Self::Pair(pair) => {
2266 let ty = pair.ty.as_pair().expect("should be a pair type");
2267 let (left_optional, right_optional) =
2268 (ty.left_type().is_optional(), ty.right_type().is_optional());
2269 let values = Arc::make_mut(&mut pair.values);
2270 values.0.visit_paths_mut(left_optional, cb)?;
2271 values.1.visit_paths_mut(right_optional, cb)?;
2272 }
2273 Self::Array(array) => {
2274 let ty = array.ty.as_array().expect("should be an array type");
2275 let optional = ty.element_type().is_optional();
2276 if let Some(elements) = &mut array.elements {
2277 for v in Arc::make_mut(elements) {
2278 v.visit_paths_mut(optional, cb)?;
2279 }
2280 }
2281 }
2282 Self::Map(map) => {
2283 let ty = map.ty.as_map().expect("should be a map type");
2284 let (key_optional, value_optional) =
2285 (ty.key_type().is_optional(), ty.value_type().is_optional());
2286 if let Some(elements) = &mut map.elements {
2287 if elements
2288 .iter()
2289 .find_map(|(k, _)| {
2290 k.as_ref().map(|v| {
2291 matches!(v, PrimitiveValue::File(_) | PrimitiveValue::Directory(_))
2292 })
2293 })
2294 .unwrap_or(false)
2295 {
2296 let elements = Arc::make_mut(elements);
2299 let new = elements
2300 .drain(..)
2301 .map(|(mut k, mut v)| {
2302 if let Some(v) = &mut k {
2303 if !v.visit_paths_mut(key_optional, cb)? {
2304 k = None;
2305 }
2306 }
2307
2308 v.visit_paths_mut(value_optional, cb)?;
2309 Ok((k, v))
2310 })
2311 .collect::<Result<Vec<_>>>()?;
2312 elements.extend(new);
2313 } else {
2314 for v in Arc::make_mut(elements).values_mut() {
2316 v.visit_paths_mut(value_optional, cb)?;
2317 }
2318 }
2319 }
2320 }
2321 Self::Object(object) => {
2322 if let Some(members) = &mut object.members {
2323 for v in Arc::make_mut(members).values_mut() {
2324 v.visit_paths_mut(false, cb)?;
2325 }
2326 }
2327 }
2328 Self::Struct(s) => {
2329 let ty = s.ty.as_struct().expect("should be a struct type");
2330 for (n, v) in Arc::make_mut(&mut s.members).iter_mut() {
2331 v.visit_paths_mut(ty.members()[n].is_optional(), cb)?;
2332 }
2333 }
2334 }
2335
2336 Ok(())
2337 }
2338}
2339
2340impl fmt::Display for CompoundValue {
2341 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2342 match self {
2343 Self::Pair(v) => v.fmt(f),
2344 Self::Array(v) => v.fmt(f),
2345 Self::Map(v) => v.fmt(f),
2346 Self::Object(v) => v.fmt(f),
2347 Self::Struct(v) => v.fmt(f),
2348 }
2349 }
2350}
2351
2352impl Coercible for CompoundValue {
2353 fn coerce(&self, target: &Type) -> Result<Self> {
2354 if target.is_union() || target.is_none() || self.ty().eq(target) {
2355 return Ok(self.clone());
2356 }
2357
2358 if let Type::Compound(target_ty, _) = target {
2359 match (self, target_ty) {
2360 (Self::Array(v), CompoundType::Array(target_ty)) => {
2362 if v.is_empty() && target_ty.is_non_empty() {
2365 bail!("cannot coerce empty array value to non-empty array type `{target}`",);
2366 }
2367
2368 return Ok(Self::Array(Array::new(
2369 target.clone(),
2370 v.as_slice().iter().cloned(),
2371 )?));
2372 }
2373 (Self::Map(v), CompoundType::Map(_)) => {
2375 return Ok(Self::Map(Map::new(
2376 target.clone(),
2377 v.iter().map(|(k, v)| {
2378 (k.clone().map(Into::into).unwrap_or(Value::None), v.clone())
2379 }),
2380 )?));
2381 }
2382 (Self::Pair(v), CompoundType::Pair(_)) => {
2384 return Ok(Self::Pair(Pair::new(
2385 target.clone(),
2386 v.values.0.clone(),
2387 v.values.1.clone(),
2388 )?));
2389 }
2390 (Self::Map(v), CompoundType::Struct(target_ty)) => {
2392 let len = v.len();
2393 let expected_len = target_ty.members().len();
2394
2395 if len != expected_len {
2396 bail!(
2397 "cannot coerce a map of {len} element{s1} to struct type `{target}` \
2398 as the struct has {expected_len} member{s2}",
2399 s1 = if len == 1 { "" } else { "s" },
2400 s2 = if expected_len == 1 { "" } else { "s" }
2401 );
2402 }
2403
2404 return Ok(Self::Struct(Struct {
2405 ty: target.clone(),
2406 name: target_ty.name().clone(),
2407 members: Arc::new(
2408 v.iter()
2409 .map(|(k, v)| {
2410 let k: String = k
2411 .as_ref()
2412 .and_then(|k| k.as_string())
2413 .with_context(|| {
2414 format!(
2415 "cannot coerce a map with a non-string key type \
2416 to struct type `{target}`"
2417 )
2418 })?
2419 .to_string();
2420 let ty = target_ty.members().get(&k).with_context(|| {
2421 format!(
2422 "cannot coerce a map with key `{k}` to struct type \
2423 `{target}` as the struct does not contain a member \
2424 with that name"
2425 )
2426 })?;
2427 let v = v.coerce(ty).with_context(|| {
2428 format!("failed to coerce value of map key `{k}")
2429 })?;
2430 Ok((k, v))
2431 })
2432 .collect::<Result<_>>()?,
2433 ),
2434 }));
2435 }
2436 (Self::Struct(Struct { members, .. }), CompoundType::Map(map_ty)) => {
2439 if map_ty.key_type().as_primitive() != Some(PrimitiveType::String) {
2440 bail!(
2441 "cannot coerce a struct or object to type `{target}` as it requires a \
2442 `String` key type"
2443 );
2444 }
2445
2446 let value_ty = map_ty.value_type();
2447 return Ok(Self::Map(Map::new_unchecked(
2448 target.clone(),
2449 members
2450 .iter()
2451 .map(|(n, v)| {
2452 let v = v
2453 .coerce(value_ty)
2454 .with_context(|| format!("failed to coerce member `{n}`"))?;
2455 Ok((PrimitiveValue::new_string(n).into(), v))
2456 })
2457 .collect::<Result<_>>()?,
2458 )));
2459 }
2460 (Self::Object(object), CompoundType::Map(map_ty)) => {
2461 if map_ty.key_type().as_primitive() != Some(PrimitiveType::String) {
2462 bail!(
2463 "cannot coerce a struct or object to type `{target}` as it requires a \
2464 `String` key type",
2465 );
2466 }
2467
2468 let value_ty = map_ty.value_type();
2469 return Ok(Self::Map(Map::new_unchecked(
2470 target.clone(),
2471 object
2472 .iter()
2473 .map(|(n, v)| {
2474 let v = v
2475 .coerce(value_ty)
2476 .with_context(|| format!("failed to coerce member `{n}`"))?;
2477 Ok((PrimitiveValue::new_string(n).into(), v))
2478 })
2479 .collect::<Result<_>>()?,
2480 )));
2481 }
2482 (Self::Object(v), CompoundType::Struct(_)) => {
2484 return Ok(Self::Struct(Struct::new(
2485 target.clone(),
2486 v.iter().map(|(k, v)| (k, v.clone())),
2487 )?));
2488 }
2489 (Self::Struct(v), CompoundType::Struct(struct_ty)) => {
2491 let len = v.members.len();
2492 let expected_len = struct_ty.members().len();
2493
2494 if len != expected_len {
2495 bail!(
2496 "cannot coerce a struct of {len} members{s1} to struct type \
2497 `{target}` as the target struct has {expected_len} member{s2}",
2498 s1 = if len == 1 { "" } else { "s" },
2499 s2 = if expected_len == 1 { "" } else { "s" }
2500 );
2501 }
2502
2503 return Ok(Self::Struct(Struct {
2504 ty: target.clone(),
2505 name: struct_ty.name().clone(),
2506 members: Arc::new(
2507 v.members
2508 .iter()
2509 .map(|(k, v)| {
2510 let ty = struct_ty.members().get(k).ok_or_else(|| {
2511 anyhow!(
2512 "cannot coerce a struct with member `{k}` to struct \
2513 type `{target}` as the target struct does not \
2514 contain a member with that name",
2515 )
2516 })?;
2517 let v = v.coerce(ty).with_context(|| {
2518 format!("failed to coerce member `{k}`")
2519 })?;
2520 Ok((k.clone(), v))
2521 })
2522 .collect::<Result<_>>()?,
2523 ),
2524 }));
2525 }
2526 _ => {}
2527 }
2528 }
2529
2530 if let Type::Object = target {
2531 match self {
2532 Self::Map(v) => {
2534 return Ok(Self::Object(Object::new(
2535 v.iter()
2536 .map(|(k, v)| {
2537 let k = k
2538 .as_ref()
2539 .and_then(|k| k.as_string())
2540 .context(
2541 "cannot coerce a map with a non-string key type to type \
2542 `Object`",
2543 )?
2544 .to_string();
2545 Ok((k, v.clone()))
2546 })
2547 .collect::<Result<IndexMap<_, _>>>()?,
2548 )));
2549 }
2550 Self::Struct(v) => {
2552 return Ok(Self::Object(Object {
2553 members: Some(v.members.clone()),
2554 }));
2555 }
2556 _ => {}
2557 };
2558 }
2559
2560 bail!(
2561 "cannot coerce a value of type `{ty}` to type `{target}`",
2562 ty = self.ty()
2563 );
2564 }
2565}
2566
2567impl From<Pair> for CompoundValue {
2568 fn from(value: Pair) -> Self {
2569 Self::Pair(value)
2570 }
2571}
2572
2573impl From<Array> for CompoundValue {
2574 fn from(value: Array) -> Self {
2575 Self::Array(value)
2576 }
2577}
2578
2579impl From<Map> for CompoundValue {
2580 fn from(value: Map) -> Self {
2581 Self::Map(value)
2582 }
2583}
2584
2585impl From<Object> for CompoundValue {
2586 fn from(value: Object) -> Self {
2587 Self::Object(value)
2588 }
2589}
2590
2591impl From<Struct> for CompoundValue {
2592 fn from(value: Struct) -> Self {
2593 Self::Struct(value)
2594 }
2595}
2596
2597#[derive(Debug)]
2599struct TaskData {
2600 name: Arc<String>,
2602 id: Arc<String>,
2604 container: Option<Arc<String>>,
2606 cpu: f64,
2608 memory: i64,
2610 gpu: Array,
2615 fpga: Array,
2620 disks: Map,
2627 end_time: Option<i64>,
2631 meta: Object,
2633 parameter_meta: Object,
2635 ext: Object,
2637}
2638
2639#[derive(Debug, Clone)]
2643pub struct TaskValue {
2644 data: Arc<TaskData>,
2646 attempt: i64,
2651 return_code: Option<i64>,
2655}
2656
2657impl TaskValue {
2658 pub(crate) fn new_v1<N: TreeNode>(
2660 name: impl Into<String>,
2661 id: impl Into<String>,
2662 definition: &v1::TaskDefinition<N>,
2663 constraints: TaskExecutionConstraints,
2664 attempt: i64,
2665 ) -> Self {
2666 Self {
2667 data: Arc::new(TaskData {
2668 name: Arc::new(name.into()),
2669 id: Arc::new(id.into()),
2670 container: constraints.container.map(Into::into),
2671 cpu: constraints.cpu,
2672 memory: constraints.memory,
2673 gpu: Array::new_unchecked(
2674 ANALYSIS_STDLIB.array_string_type().clone(),
2675 constraints
2676 .gpu
2677 .into_iter()
2678 .map(|v| PrimitiveValue::new_string(v).into())
2679 .collect(),
2680 ),
2681 fpga: Array::new_unchecked(
2682 ANALYSIS_STDLIB.array_string_type().clone(),
2683 constraints
2684 .fpga
2685 .into_iter()
2686 .map(|v| PrimitiveValue::new_string(v).into())
2687 .collect(),
2688 ),
2689 disks: Map::new_unchecked(
2690 ANALYSIS_STDLIB.map_string_int_type().clone(),
2691 constraints
2692 .disks
2693 .into_iter()
2694 .map(|(k, v)| (Some(PrimitiveValue::new_string(k)), v.into()))
2695 .collect(),
2696 ),
2697 end_time: None,
2698 meta: definition
2699 .metadata()
2700 .map(|s| Object::from_v1_metadata(s.items()))
2701 .unwrap_or_else(Object::empty),
2702 parameter_meta: definition
2703 .parameter_metadata()
2704 .map(|s| Object::from_v1_metadata(s.items()))
2705 .unwrap_or_else(Object::empty),
2706 ext: Object::empty(),
2707 }),
2708 attempt,
2709 return_code: None,
2710 }
2711 }
2712
2713 pub fn name(&self) -> &Arc<String> {
2715 &self.data.name
2716 }
2717
2718 pub fn id(&self) -> &Arc<String> {
2720 &self.data.id
2721 }
2722
2723 pub fn container(&self) -> Option<&Arc<String>> {
2725 self.data.container.as_ref()
2726 }
2727
2728 pub fn cpu(&self) -> f64 {
2730 self.data.cpu
2731 }
2732
2733 pub fn memory(&self) -> i64 {
2735 self.data.memory
2736 }
2737
2738 pub fn gpu(&self) -> &Array {
2743 &self.data.gpu
2744 }
2745
2746 pub fn fpga(&self) -> &Array {
2751 &self.data.fpga
2752 }
2753
2754 pub fn disks(&self) -> &Map {
2761 &self.data.disks
2762 }
2763
2764 pub fn attempt(&self) -> i64 {
2769 self.attempt
2770 }
2771
2772 pub fn end_time(&self) -> Option<i64> {
2776 self.data.end_time
2777 }
2778
2779 pub fn return_code(&self) -> Option<i64> {
2783 self.return_code
2784 }
2785
2786 pub fn meta(&self) -> &Object {
2788 &self.data.meta
2789 }
2790
2791 pub fn parameter_meta(&self) -> &Object {
2793 &self.data.parameter_meta
2794 }
2795
2796 pub fn ext(&self) -> &Object {
2798 &self.data.ext
2799 }
2800
2801 pub(crate) fn set_return_code(&mut self, code: i32) {
2803 self.return_code = Some(code as i64);
2804 }
2805
2806 pub(crate) fn set_attempt(&mut self, attempt: i64) {
2808 self.attempt = attempt;
2809 }
2810
2811 pub fn field(&self, name: &str) -> Option<Value> {
2815 match name {
2816 n if n == TASK_FIELD_NAME => {
2817 Some(PrimitiveValue::String(self.data.name.clone()).into())
2818 }
2819 n if n == TASK_FIELD_ID => Some(PrimitiveValue::String(self.data.id.clone()).into()),
2820 n if n == TASK_FIELD_CONTAINER => Some(
2821 self.data
2822 .container
2823 .clone()
2824 .map(|c| PrimitiveValue::String(c).into())
2825 .unwrap_or(Value::None),
2826 ),
2827 n if n == TASK_FIELD_CPU => Some(self.data.cpu.into()),
2828 n if n == TASK_FIELD_MEMORY => Some(self.data.memory.into()),
2829 n if n == TASK_FIELD_GPU => Some(self.data.gpu.clone().into()),
2830 n if n == TASK_FIELD_FPGA => Some(self.data.fpga.clone().into()),
2831 n if n == TASK_FIELD_DISKS => Some(self.data.disks.clone().into()),
2832 n if n == TASK_FIELD_ATTEMPT => Some(self.attempt.into()),
2833 n if n == TASK_FIELD_END_TIME => {
2834 Some(self.data.end_time.map(Into::into).unwrap_or(Value::None))
2835 }
2836 n if n == TASK_FIELD_RETURN_CODE => {
2837 Some(self.return_code.map(Into::into).unwrap_or(Value::None))
2838 }
2839 n if n == TASK_FIELD_META => Some(self.data.meta.clone().into()),
2840 n if n == TASK_FIELD_PARAMETER_META => Some(self.data.parameter_meta.clone().into()),
2841 n if n == TASK_FIELD_EXT => Some(self.data.ext.clone().into()),
2842 _ => None,
2843 }
2844 }
2845}
2846
2847#[derive(Debug, Clone)]
2851pub struct HintsValue(Object);
2852
2853impl HintsValue {
2854 pub fn as_object(&self) -> &Object {
2856 &self.0
2857 }
2858}
2859
2860impl fmt::Display for HintsValue {
2861 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2862 write!(f, "hints {{")?;
2863
2864 for (i, (k, v)) in self.0.iter().enumerate() {
2865 if i > 0 {
2866 write!(f, ", ")?;
2867 }
2868
2869 write!(f, "{k}: {v}")?;
2870 }
2871
2872 write!(f, "}}")
2873 }
2874}
2875
2876impl From<Object> for HintsValue {
2877 fn from(value: Object) -> Self {
2878 Self(value)
2879 }
2880}
2881
2882#[derive(Debug, Clone)]
2886pub struct InputValue(Object);
2887
2888impl InputValue {
2889 pub fn as_object(&self) -> &Object {
2891 &self.0
2892 }
2893}
2894
2895impl fmt::Display for InputValue {
2896 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2897 write!(f, "input {{")?;
2898
2899 for (i, (k, v)) in self.0.iter().enumerate() {
2900 if i > 0 {
2901 write!(f, ", ")?;
2902 }
2903
2904 write!(f, "{k}: {v}")?;
2905 }
2906
2907 write!(f, "}}")
2908 }
2909}
2910
2911impl From<Object> for InputValue {
2912 fn from(value: Object) -> Self {
2913 Self(value)
2914 }
2915}
2916
2917#[derive(Debug, Clone)]
2921pub struct OutputValue(Object);
2922
2923impl OutputValue {
2924 pub fn as_object(&self) -> &Object {
2926 &self.0
2927 }
2928}
2929
2930impl fmt::Display for OutputValue {
2931 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2932 write!(f, "output {{")?;
2933
2934 for (i, (k, v)) in self.0.iter().enumerate() {
2935 if i > 0 {
2936 write!(f, ", ")?;
2937 }
2938
2939 write!(f, "{k}: {v}")?;
2940 }
2941
2942 write!(f, "}}")
2943 }
2944}
2945
2946impl From<Object> for OutputValue {
2947 fn from(value: Object) -> Self {
2948 Self(value)
2949 }
2950}
2951
2952#[derive(Debug, Clone)]
2956pub struct CallValue {
2957 ty: CallType,
2959 outputs: Arc<Outputs>,
2961}
2962
2963impl CallValue {
2964 pub(crate) fn new_unchecked(ty: CallType, outputs: Arc<Outputs>) -> Self {
2967 Self { ty, outputs }
2968 }
2969
2970 pub fn ty(&self) -> &CallType {
2972 &self.ty
2973 }
2974
2975 pub fn outputs(&self) -> &Outputs {
2977 self.outputs.as_ref()
2978 }
2979}
2980
2981impl fmt::Display for CallValue {
2982 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2983 write!(f, "call output {{")?;
2984
2985 for (i, (k, v)) in self.outputs.iter().enumerate() {
2986 if i > 0 {
2987 write!(f, ", ")?;
2988 }
2989
2990 write!(f, "{k}: {v}")?;
2991 }
2992
2993 write!(f, "}}")
2994 }
2995}
2996
2997pub struct ValueSerializer<'a> {
2999 value: &'a Value,
3001 allow_pairs: bool,
3004}
3005
3006impl<'a> ValueSerializer<'a> {
3007 pub fn new(value: &'a Value, allow_pairs: bool) -> Self {
3009 Self { value, allow_pairs }
3010 }
3011}
3012
3013impl serde::Serialize for ValueSerializer<'_> {
3014 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
3015 where
3016 S: serde::Serializer,
3017 {
3018 use serde::ser::Error;
3019
3020 match &self.value {
3021 Value::None => serializer.serialize_none(),
3022 Value::Primitive(v) => v.serialize(serializer),
3023 Value::Compound(v) => {
3024 CompoundValueSerializer::new(v, self.allow_pairs).serialize(serializer)
3025 }
3026 Value::Task(_)
3027 | Value::Hints(_)
3028 | Value::Input(_)
3029 | Value::Output(_)
3030 | Value::Call(_) => Err(S::Error::custom("value cannot be serialized")),
3031 }
3032 }
3033}
3034
3035pub struct CompoundValueSerializer<'a> {
3037 value: &'a CompoundValue,
3039 allow_pairs: bool,
3042}
3043
3044impl<'a> CompoundValueSerializer<'a> {
3045 pub fn new(value: &'a CompoundValue, allow_pairs: bool) -> Self {
3047 Self { value, allow_pairs }
3048 }
3049}
3050
3051impl serde::Serialize for CompoundValueSerializer<'_> {
3052 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
3053 where
3054 S: serde::Serializer,
3055 {
3056 use serde::ser::Error;
3057
3058 match &self.value {
3059 CompoundValue::Pair(pair) if self.allow_pairs => {
3060 let mut state = serializer.serialize_map(Some(2))?;
3061 let left = ValueSerializer::new(pair.left(), self.allow_pairs);
3062 let right = ValueSerializer::new(pair.right(), self.allow_pairs);
3063 state.serialize_entry("left", &left)?;
3064 state.serialize_entry("right", &right)?;
3065 state.end()
3066 }
3067 CompoundValue::Pair(_) => Err(S::Error::custom("a pair cannot be serialized")),
3068 CompoundValue::Array(v) => {
3069 let mut s = serializer.serialize_seq(Some(v.len()))?;
3070 for v in v.as_slice() {
3071 s.serialize_element(&ValueSerializer::new(v, self.allow_pairs))?;
3072 }
3073
3074 s.end()
3075 }
3076 CompoundValue::Map(v) => {
3077 if !v
3078 .ty()
3079 .as_map()
3080 .expect("type should be a map")
3081 .key_type()
3082 .is_coercible_to(&PrimitiveType::String.into())
3083 {
3084 return Err(S::Error::custom(
3085 "only maps with `String` key types may be serialized",
3086 ));
3087 }
3088
3089 let mut s = serializer.serialize_map(Some(v.len()))?;
3090 for (k, v) in v.iter() {
3091 s.serialize_entry(k, &ValueSerializer::new(v, self.allow_pairs))?;
3092 }
3093
3094 s.end()
3095 }
3096 CompoundValue::Object(object) => {
3097 let mut s = serializer.serialize_map(Some(object.len()))?;
3098 for (k, v) in object.iter() {
3099 s.serialize_entry(k, &ValueSerializer::new(v, self.allow_pairs))?;
3100 }
3101
3102 s.end()
3103 }
3104 CompoundValue::Struct(Struct { members, .. }) => {
3105 let mut s = serializer.serialize_map(Some(members.len()))?;
3106 for (k, v) in members.iter() {
3107 s.serialize_entry(k, &ValueSerializer::new(v, self.allow_pairs))?;
3108 }
3109
3110 s.end()
3111 }
3112 }
3113 }
3114}
3115
3116#[cfg(test)]
3117mod test {
3118 use approx::assert_relative_eq;
3119 use pretty_assertions::assert_eq;
3120 use wdl_analysis::types::ArrayType;
3121 use wdl_analysis::types::MapType;
3122 use wdl_analysis::types::PairType;
3123 use wdl_analysis::types::StructType;
3124
3125 use super::*;
3126
3127 #[test]
3128 fn boolean_coercion() {
3129 assert_eq!(
3131 Value::from(false)
3132 .coerce(&PrimitiveType::Boolean.into())
3133 .expect("should coerce")
3134 .unwrap_boolean(),
3135 Value::from(false).unwrap_boolean()
3136 );
3137 assert_eq!(
3139 format!(
3140 "{e:?}",
3141 e = Value::from(true)
3142 .coerce(&PrimitiveType::String.into())
3143 .unwrap_err()
3144 ),
3145 "cannot coerce type `Boolean` to type `String`"
3146 );
3147 }
3148
3149 #[test]
3150 fn boolean_display() {
3151 assert_eq!(Value::from(false).to_string(), "false");
3152 assert_eq!(Value::from(true).to_string(), "true");
3153 }
3154
3155 #[test]
3156 fn integer_coercion() {
3157 assert_eq!(
3159 Value::from(12345)
3160 .coerce(&PrimitiveType::Integer.into())
3161 .expect("should coerce")
3162 .unwrap_integer(),
3163 Value::from(12345).unwrap_integer()
3164 );
3165 assert_relative_eq!(
3167 Value::from(12345)
3168 .coerce(&PrimitiveType::Float.into())
3169 .expect("should coerce")
3170 .unwrap_float(),
3171 Value::from(12345.0).unwrap_float()
3172 );
3173 assert_eq!(
3175 format!(
3176 "{e:?}",
3177 e = Value::from(12345)
3178 .coerce(&PrimitiveType::Boolean.into())
3179 .unwrap_err()
3180 ),
3181 "cannot coerce type `Int` to type `Boolean`"
3182 );
3183 }
3184
3185 #[test]
3186 fn integer_display() {
3187 assert_eq!(Value::from(12345).to_string(), "12345");
3188 assert_eq!(Value::from(-12345).to_string(), "-12345");
3189 }
3190
3191 #[test]
3192 fn float_coercion() {
3193 assert_relative_eq!(
3195 Value::from(12345.0)
3196 .coerce(&PrimitiveType::Float.into())
3197 .expect("should coerce")
3198 .unwrap_float(),
3199 Value::from(12345.0).unwrap_float()
3200 );
3201 assert_eq!(
3203 format!(
3204 "{e:?}",
3205 e = Value::from(12345.0)
3206 .coerce(&PrimitiveType::Integer.into())
3207 .unwrap_err()
3208 ),
3209 "cannot coerce type `Float` to type `Int`"
3210 );
3211 }
3212
3213 #[test]
3214 fn float_display() {
3215 assert_eq!(Value::from(12345.12345).to_string(), "12345.123450");
3216 assert_eq!(Value::from(-12345.12345).to_string(), "-12345.123450");
3217 }
3218
3219 #[test]
3220 fn string_coercion() {
3221 let value = PrimitiveValue::new_string("foo");
3222 assert_eq!(
3224 value
3225 .coerce(&PrimitiveType::String.into())
3226 .expect("should coerce"),
3227 value
3228 );
3229 assert_eq!(
3231 value
3232 .coerce(&PrimitiveType::File.into())
3233 .expect("should coerce"),
3234 PrimitiveValue::File(value.as_string().expect("should be string").clone())
3235 );
3236 assert_eq!(
3238 value
3239 .coerce(&PrimitiveType::Directory.into())
3240 .expect("should coerce"),
3241 PrimitiveValue::Directory(value.as_string().expect("should be string").clone())
3242 );
3243 assert_eq!(
3245 format!(
3246 "{e:?}",
3247 e = value.coerce(&PrimitiveType::Boolean.into()).unwrap_err()
3248 ),
3249 "cannot coerce type `String` to type `Boolean`"
3250 );
3251 }
3252
3253 #[test]
3254 fn string_display() {
3255 let value = PrimitiveValue::new_string("hello world!");
3256 assert_eq!(value.to_string(), "\"hello world!\"");
3257 }
3258
3259 #[test]
3260 fn file_coercion() {
3261 let value = PrimitiveValue::new_file("foo");
3262
3263 assert_eq!(
3265 value
3266 .coerce(&PrimitiveType::File.into())
3267 .expect("should coerce"),
3268 value
3269 );
3270 assert_eq!(
3272 value
3273 .coerce(&PrimitiveType::String.into())
3274 .expect("should coerce"),
3275 PrimitiveValue::String(value.as_file().expect("should be file").clone())
3276 );
3277 assert_eq!(
3279 format!(
3280 "{e:?}",
3281 e = value.coerce(&PrimitiveType::Directory.into()).unwrap_err()
3282 ),
3283 "cannot coerce type `File` to type `Directory`"
3284 );
3285 }
3286
3287 #[test]
3288 fn file_display() {
3289 let value = PrimitiveValue::new_file("/foo/bar/baz.txt");
3290 assert_eq!(value.to_string(), "\"/foo/bar/baz.txt\"");
3291 }
3292
3293 #[test]
3294 fn directory_coercion() {
3295 let value = PrimitiveValue::new_directory("foo");
3296
3297 assert_eq!(
3299 value
3300 .coerce(&PrimitiveType::Directory.into())
3301 .expect("should coerce"),
3302 value
3303 );
3304 assert_eq!(
3306 value
3307 .coerce(&PrimitiveType::String.into())
3308 .expect("should coerce"),
3309 PrimitiveValue::String(value.as_directory().expect("should be directory").clone())
3310 );
3311 assert_eq!(
3313 format!(
3314 "{e:?}",
3315 e = value.coerce(&PrimitiveType::File.into()).unwrap_err()
3316 ),
3317 "cannot coerce type `Directory` to type `File`"
3318 );
3319 }
3320
3321 #[test]
3322 fn directory_display() {
3323 let value = PrimitiveValue::new_directory("/foo/bar/baz");
3324 assert_eq!(value.to_string(), "\"/foo/bar/baz\"");
3325 }
3326
3327 #[test]
3328 fn none_coercion() {
3329 assert!(
3331 Value::None
3332 .coerce(&Type::from(PrimitiveType::String).optional())
3333 .expect("should coerce")
3334 .is_none(),
3335 );
3336
3337 assert_eq!(
3339 format!(
3340 "{e:?}",
3341 e = Value::None
3342 .coerce(&PrimitiveType::String.into())
3343 .unwrap_err()
3344 ),
3345 "cannot coerce `None` to non-optional type `String`"
3346 );
3347 }
3348
3349 #[test]
3350 fn none_display() {
3351 assert_eq!(Value::None.to_string(), "None");
3352 }
3353
3354 #[test]
3355 fn array_coercion() {
3356 let src_ty: Type = ArrayType::new(PrimitiveType::Integer).into();
3357 let target_ty: Type = ArrayType::new(PrimitiveType::Float).into();
3358
3359 let src: CompoundValue = Array::new(src_ty, [1, 2, 3])
3361 .expect("should create array value")
3362 .into();
3363 let target = src.coerce(&target_ty).expect("should coerce");
3364 assert_eq!(
3365 target.unwrap_array().to_string(),
3366 "[1.000000, 2.000000, 3.000000]"
3367 );
3368
3369 let target_ty: Type = ArrayType::new(PrimitiveType::String).into();
3371 assert_eq!(
3372 format!("{e:?}", e = src.coerce(&target_ty).unwrap_err()),
3373 r#"failed to coerce array element at index 0
3374
3375Caused by:
3376 cannot coerce type `Int` to type `String`"#
3377 );
3378 }
3379
3380 #[test]
3381 fn non_empty_array_coercion() {
3382 let ty: Type = ArrayType::new(PrimitiveType::String).into();
3383 let target_ty: Type = ArrayType::non_empty(PrimitiveType::String).into();
3384
3385 let string = PrimitiveValue::new_string("foo");
3387 let value: Value = Array::new(ty.clone(), [string])
3388 .expect("should create array")
3389 .into();
3390 assert!(value.coerce(&target_ty).is_ok(), "should coerce");
3391
3392 let value: Value = Array::new::<Value>(ty, [])
3394 .expect("should create array")
3395 .into();
3396 assert_eq!(
3397 format!("{e:?}", e = value.coerce(&target_ty).unwrap_err()),
3398 "cannot coerce empty array value to non-empty array type `Array[String]+`"
3399 );
3400 }
3401
3402 #[test]
3403 fn array_display() {
3404 let ty: Type = ArrayType::new(PrimitiveType::Integer).into();
3405 let value: Value = Array::new(ty, [1, 2, 3])
3406 .expect("should create array")
3407 .into();
3408
3409 assert_eq!(value.to_string(), "[1, 2, 3]");
3410 }
3411
3412 #[test]
3413 fn map_coerce() {
3414 let key1 = PrimitiveValue::new_file("foo");
3415 let value1 = PrimitiveValue::new_string("bar");
3416 let key2 = PrimitiveValue::new_file("baz");
3417 let value2 = PrimitiveValue::new_string("qux");
3418
3419 let ty = MapType::new(PrimitiveType::File, PrimitiveType::String);
3420 let value: Value = Map::new(ty, [(key1, value1), (key2, value2)])
3421 .expect("should create map value")
3422 .into();
3423
3424 let ty = MapType::new(PrimitiveType::String, PrimitiveType::File).into();
3426 let value = value.coerce(&ty).expect("value should coerce");
3427 assert_eq!(value.to_string(), r#"{"foo": "bar", "baz": "qux"}"#);
3428
3429 let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::File).into();
3431 assert_eq!(
3432 format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3433 r#"failed to coerce map key for element at index 0
3434
3435Caused by:
3436 cannot coerce type `String` to type `Int`"#
3437 );
3438
3439 let ty = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
3441 assert_eq!(
3442 format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3443 r#"failed to coerce map value for element at index 0
3444
3445Caused by:
3446 cannot coerce type `File` to type `Int`"#
3447 );
3448
3449 let ty = StructType::new(
3451 "Foo",
3452 [("foo", PrimitiveType::File), ("baz", PrimitiveType::File)],
3453 )
3454 .into();
3455 let struct_value = value.coerce(&ty).expect("value should coerce");
3456 assert_eq!(struct_value.to_string(), r#"Foo {foo: "bar", baz: "qux"}"#);
3457
3458 let ty = StructType::new(
3460 "Foo",
3461 [
3462 ("foo", PrimitiveType::File),
3463 ("baz", PrimitiveType::File),
3464 ("qux", PrimitiveType::File),
3465 ],
3466 )
3467 .into();
3468 assert_eq!(
3469 format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3470 "cannot coerce a map of 2 elements to struct type `Foo` as the struct has 3 members"
3471 );
3472
3473 let object_value = value.coerce(&Type::Object).expect("value should coerce");
3475 assert_eq!(
3476 object_value.to_string(),
3477 r#"object {foo: "bar", baz: "qux"}"#
3478 );
3479 }
3480
3481 #[test]
3482 fn map_display() {
3483 let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::Boolean);
3484 let value: Value = Map::new(ty, [(1, true), (2, false)])
3485 .expect("should create map value")
3486 .into();
3487 assert_eq!(value.to_string(), "{1: true, 2: false}");
3488 }
3489
3490 #[test]
3491 fn pair_coercion() {
3492 let left = PrimitiveValue::new_file("foo");
3493 let right = PrimitiveValue::new_string("bar");
3494
3495 let ty = PairType::new(PrimitiveType::File, PrimitiveType::String);
3496 let value: Value = Pair::new(ty, left, right)
3497 .expect("should create pair value")
3498 .into();
3499
3500 let ty = PairType::new(PrimitiveType::String, PrimitiveType::File).into();
3502 let value = value.coerce(&ty).expect("value should coerce");
3503 assert_eq!(value.to_string(), r#"("foo", "bar")"#);
3504
3505 let ty = PairType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
3507 assert_eq!(
3508 format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3509 r#"failed to coerce pair's left value
3510
3511Caused by:
3512 cannot coerce type `String` to type `Int`"#
3513 );
3514 }
3515
3516 #[test]
3517 fn pair_display() {
3518 let ty = PairType::new(PrimitiveType::Integer, PrimitiveType::Boolean);
3519 let value: Value = Pair::new(ty, 12345, false)
3520 .expect("should create pair value")
3521 .into();
3522 assert_eq!(value.to_string(), "(12345, false)");
3523 }
3524
3525 #[test]
3526 fn struct_coercion() {
3527 let ty = StructType::new(
3528 "Foo",
3529 [
3530 ("foo", PrimitiveType::Float),
3531 ("bar", PrimitiveType::Float),
3532 ("baz", PrimitiveType::Float),
3533 ],
3534 );
3535 let value: Value = Struct::new(ty, [("foo", 1.0), ("bar", 2.0), ("baz", 3.0)])
3536 .expect("should create map value")
3537 .into();
3538
3539 let ty = MapType::new(PrimitiveType::String, PrimitiveType::Float).into();
3541 let map_value = value.coerce(&ty).expect("value should coerce");
3542 assert_eq!(
3543 map_value.to_string(),
3544 r#"{"foo": 1.000000, "bar": 2.000000, "baz": 3.000000}"#
3545 );
3546
3547 let ty = StructType::new(
3549 "Bar",
3550 [
3551 ("foo", PrimitiveType::Float),
3552 ("bar", PrimitiveType::Float),
3553 ("baz", PrimitiveType::Float),
3554 ],
3555 )
3556 .into();
3557 let struct_value = value.coerce(&ty).expect("value should coerce");
3558 assert_eq!(
3559 struct_value.to_string(),
3560 r#"Bar {foo: 1.000000, bar: 2.000000, baz: 3.000000}"#
3561 );
3562
3563 let object_value = value.coerce(&Type::Object).expect("value should coerce");
3565 assert_eq!(
3566 object_value.to_string(),
3567 r#"object {foo: 1.000000, bar: 2.000000, baz: 3.000000}"#
3568 );
3569 }
3570
3571 #[test]
3572 fn struct_display() {
3573 let ty = StructType::new(
3574 "Foo",
3575 [
3576 ("foo", PrimitiveType::Float),
3577 ("bar", PrimitiveType::String),
3578 ("baz", PrimitiveType::Integer),
3579 ],
3580 );
3581 let value: Value = Struct::new(
3582 ty,
3583 [
3584 ("foo", Value::from(1.101)),
3585 ("bar", PrimitiveValue::new_string("foo").into()),
3586 ("baz", 1234.into()),
3587 ],
3588 )
3589 .expect("should create map value")
3590 .into();
3591 assert_eq!(
3592 value.to_string(),
3593 r#"Foo {foo: 1.101000, bar: "foo", baz: 1234}"#
3594 );
3595 }
3596
3597 #[test]
3598 fn pair_serialization() {
3599 let pair_ty = PairType::new(PrimitiveType::File, PrimitiveType::String);
3600 let pair: Value = Pair::new(
3601 pair_ty,
3602 PrimitiveValue::new_file("foo"),
3603 PrimitiveValue::new_string("bar"),
3604 )
3605 .expect("should create pair value")
3606 .into();
3607 let value_serializer = ValueSerializer::new(&pair, true);
3609 let serialized = serde_json::to_string(&value_serializer).expect("should serialize");
3610 assert_eq!(serialized, r#"{"left":"foo","right":"bar"}"#);
3611
3612 let value_serializer = ValueSerializer::new(&pair, false);
3614 assert!(serde_json::to_string(&value_serializer).is_err());
3615
3616 let array_ty = ArrayType::new(PairType::new(PrimitiveType::File, PrimitiveType::String));
3617 let array: Value = Array::new(array_ty, [pair])
3618 .expect("should create array value")
3619 .into();
3620
3621 let value_serializer = ValueSerializer::new(&array, true);
3623 let serialized = serde_json::to_string(&value_serializer).expect("should serialize");
3624 assert_eq!(serialized, r#"[{"left":"foo","right":"bar"}]"#);
3625 }
3626}