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 serde::ser::SerializeMap;
18use serde::ser::SerializeSeq;
19use wdl_analysis::stdlib::STDLIB as ANALYSIS_STDLIB;
20use wdl_analysis::types::ArrayType;
21use wdl_analysis::types::CallType;
22use wdl_analysis::types::Coercible as _;
23use wdl_analysis::types::CompoundType;
24use wdl_analysis::types::Optional;
25use wdl_analysis::types::PrimitiveType;
26use wdl_analysis::types::Type;
27use wdl_ast::AstToken;
28use wdl_ast::TreeNode;
29use wdl_ast::v1;
30use wdl_ast::v1::TASK_FIELD_ATTEMPT;
31use wdl_ast::v1::TASK_FIELD_CONTAINER;
32use wdl_ast::v1::TASK_FIELD_CPU;
33use wdl_ast::v1::TASK_FIELD_DISKS;
34use wdl_ast::v1::TASK_FIELD_END_TIME;
35use wdl_ast::v1::TASK_FIELD_EXT;
36use wdl_ast::v1::TASK_FIELD_FPGA;
37use wdl_ast::v1::TASK_FIELD_GPU;
38use wdl_ast::v1::TASK_FIELD_ID;
39use wdl_ast::v1::TASK_FIELD_MEMORY;
40use wdl_ast::v1::TASK_FIELD_META;
41use wdl_ast::v1::TASK_FIELD_NAME;
42use wdl_ast::v1::TASK_FIELD_PARAMETER_META;
43use wdl_ast::v1::TASK_FIELD_RETURN_CODE;
44use wdl_grammar::lexer::v1::is_ident;
45
46use crate::EvaluationContext;
47use crate::Outputs;
48use crate::TaskExecutionConstraints;
49use crate::path;
50
51pub trait Coercible: Sized {
53 fn coerce(&self, target: &Type) -> Result<Self>;
57}
58
59#[derive(Debug, Clone)]
63pub enum Value {
64 None,
66 Primitive(PrimitiveValue),
68 Compound(CompoundValue),
70 Task(TaskValue),
75 Hints(HintsValue),
79 Input(InputValue),
83 Output(OutputValue),
87 Call(CallValue),
89}
90
91impl Value {
92 pub fn from_v1_metadata<N: TreeNode>(value: &v1::MetadataValue<N>) -> Self {
98 match value {
99 v1::MetadataValue::Boolean(v) => v.value().into(),
100 v1::MetadataValue::Integer(v) => v.value().expect("number should be in range").into(),
101 v1::MetadataValue::Float(v) => v.value().expect("number should be in range").into(),
102 v1::MetadataValue::String(v) => PrimitiveValue::new_string(
103 v.text()
104 .expect("metadata strings shouldn't have placeholders")
105 .text(),
106 )
107 .into(),
108 v1::MetadataValue::Null(_) => Self::None,
109 v1::MetadataValue::Object(o) => Object::from_v1_metadata(o.items()).into(),
110 v1::MetadataValue::Array(a) => Array::new_unchecked(
111 ANALYSIS_STDLIB.array_object_type().clone(),
112 a.elements().map(|v| Value::from_v1_metadata(&v)).collect(),
113 )
114 .into(),
115 }
116 }
117
118 pub fn ty(&self) -> Type {
120 match self {
121 Self::None => Type::None,
122 Self::Primitive(v) => v.ty(),
123 Self::Compound(v) => v.ty(),
124 Self::Task(_) => Type::Task,
125 Self::Hints(_) => Type::Hints,
126 Self::Input(_) => Type::Input,
127 Self::Output(_) => Type::Output,
128 Self::Call(v) => Type::Call(v.ty.clone()),
129 }
130 }
131
132 pub fn is_none(&self) -> bool {
134 matches!(self, Self::None)
135 }
136
137 pub fn as_primitive(&self) -> Option<&PrimitiveValue> {
141 match self {
142 Self::Primitive(v) => Some(v),
143 _ => None,
144 }
145 }
146
147 pub fn as_compound(&self) -> Option<&CompoundValue> {
151 match self {
152 Self::Compound(v) => Some(v),
153 _ => None,
154 }
155 }
156
157 pub fn as_boolean(&self) -> Option<bool> {
161 match self {
162 Self::Primitive(PrimitiveValue::Boolean(v)) => Some(*v),
163 _ => None,
164 }
165 }
166
167 pub fn unwrap_boolean(self) -> bool {
173 match self {
174 Self::Primitive(PrimitiveValue::Boolean(v)) => v,
175 _ => panic!("value is not a boolean"),
176 }
177 }
178
179 pub fn as_integer(&self) -> Option<i64> {
183 match self {
184 Self::Primitive(PrimitiveValue::Integer(v)) => Some(*v),
185 _ => None,
186 }
187 }
188
189 pub fn unwrap_integer(self) -> i64 {
195 match self {
196 Self::Primitive(PrimitiveValue::Integer(v)) => v,
197 _ => panic!("value is not an integer"),
198 }
199 }
200
201 pub fn as_float(&self) -> Option<f64> {
205 match self {
206 Self::Primitive(PrimitiveValue::Float(v)) => Some((*v).into()),
207 _ => None,
208 }
209 }
210
211 pub fn unwrap_float(self) -> f64 {
217 match self {
218 Self::Primitive(PrimitiveValue::Float(v)) => v.into(),
219 _ => panic!("value is not a float"),
220 }
221 }
222
223 pub fn as_string(&self) -> Option<&Arc<String>> {
227 match self {
228 Self::Primitive(PrimitiveValue::String(s)) => Some(s),
229 _ => None,
230 }
231 }
232
233 pub fn unwrap_string(self) -> Arc<String> {
239 match self {
240 Self::Primitive(PrimitiveValue::String(s)) => s,
241 _ => panic!("value is not a string"),
242 }
243 }
244
245 pub fn as_file(&self) -> Option<&Arc<String>> {
249 match self {
250 Self::Primitive(PrimitiveValue::File(s)) => Some(s),
251 _ => None,
252 }
253 }
254
255 pub fn unwrap_file(self) -> Arc<String> {
261 match self {
262 Self::Primitive(PrimitiveValue::File(s)) => s,
263 _ => panic!("value is not a file"),
264 }
265 }
266
267 pub fn as_directory(&self) -> Option<&Arc<String>> {
271 match self {
272 Self::Primitive(PrimitiveValue::Directory(s)) => Some(s),
273 _ => None,
274 }
275 }
276
277 pub fn unwrap_directory(self) -> Arc<String> {
283 match self {
284 Self::Primitive(PrimitiveValue::Directory(s)) => s,
285 _ => panic!("value is not a directory"),
286 }
287 }
288
289 pub fn as_pair(&self) -> Option<&Pair> {
293 match self {
294 Self::Compound(CompoundValue::Pair(v)) => Some(v),
295 _ => None,
296 }
297 }
298
299 pub fn unwrap_pair(self) -> Pair {
305 match self {
306 Self::Compound(CompoundValue::Pair(v)) => v,
307 _ => panic!("value is not a pair"),
308 }
309 }
310
311 pub fn as_array(&self) -> Option<&Array> {
315 match self {
316 Self::Compound(CompoundValue::Array(v)) => Some(v),
317 _ => None,
318 }
319 }
320
321 pub fn unwrap_array(self) -> Array {
327 match self {
328 Self::Compound(CompoundValue::Array(v)) => v,
329 _ => panic!("value is not an array"),
330 }
331 }
332
333 pub fn as_map(&self) -> Option<&Map> {
337 match self {
338 Self::Compound(CompoundValue::Map(v)) => Some(v),
339 _ => None,
340 }
341 }
342
343 pub fn unwrap_map(self) -> Map {
349 match self {
350 Self::Compound(CompoundValue::Map(v)) => v,
351 _ => panic!("value is not a map"),
352 }
353 }
354
355 pub fn as_object(&self) -> Option<&Object> {
359 match self {
360 Self::Compound(CompoundValue::Object(v)) => Some(v),
361 _ => None,
362 }
363 }
364
365 pub fn unwrap_object(self) -> Object {
371 match self {
372 Self::Compound(CompoundValue::Object(v)) => v,
373 _ => panic!("value is not an object"),
374 }
375 }
376
377 pub fn as_struct(&self) -> Option<&Struct> {
381 match self {
382 Self::Compound(CompoundValue::Struct(v)) => Some(v),
383 _ => None,
384 }
385 }
386
387 pub fn unwrap_struct(self) -> Struct {
393 match self {
394 Self::Compound(CompoundValue::Struct(v)) => v,
395 _ => panic!("value is not a struct"),
396 }
397 }
398
399 pub fn as_task(&self) -> Option<&TaskValue> {
403 match self {
404 Self::Task(v) => Some(v),
405 _ => None,
406 }
407 }
408
409 pub(crate) fn as_task_mut(&mut self) -> Option<&mut TaskValue> {
413 match self {
414 Self::Task(v) => Some(v),
415 _ => None,
416 }
417 }
418
419 pub fn unwrap_task(self) -> TaskValue {
425 match self {
426 Self::Task(v) => v,
427 _ => panic!("value is not a task"),
428 }
429 }
430
431 pub fn as_hints(&self) -> Option<&HintsValue> {
435 match self {
436 Self::Hints(v) => Some(v),
437 _ => None,
438 }
439 }
440
441 pub fn unwrap_hints(self) -> HintsValue {
447 match self {
448 Self::Hints(v) => v,
449 _ => panic!("value is not a hints value"),
450 }
451 }
452
453 pub fn as_call(&self) -> Option<&CallValue> {
457 match self {
458 Self::Call(v) => Some(v),
459 _ => None,
460 }
461 }
462
463 pub fn unwrap_call(self) -> CallValue {
469 match self {
470 Self::Call(v) => v,
471 _ => panic!("value is not a call value"),
472 }
473 }
474
475 pub(crate) fn visit_paths(
479 &self,
480 optional: bool,
481 cb: &mut impl FnMut(bool, &PrimitiveValue) -> Result<()>,
482 ) -> Result<()> {
483 match self {
484 Self::Primitive(v) => v.visit_paths(optional, cb),
485 Self::Compound(v) => v.visit_paths(cb),
486 _ => Ok(()),
487 }
488 }
489
490 pub(crate) fn visit_paths_mut(
497 &mut self,
498 optional: bool,
499 cb: &mut impl FnMut(bool, &mut PrimitiveValue) -> Result<bool>,
500 ) -> Result<()> {
501 match self {
502 Self::Primitive(v) => {
503 if !v.visit_paths_mut(optional, cb)? {
504 *self = Value::None;
505 }
506
507 Ok(())
508 }
509 Self::Compound(v) => v.visit_paths_mut(cb),
510 _ => Ok(()),
511 }
512 }
513
514 pub(crate) fn clone_as_required(&self) -> Self {
518 match self {
519 Self::Compound(v) => Self::Compound(v.clone_as_required()),
520 _ => self.clone(),
521 }
522 }
523
524 pub(crate) fn clone_as_optional(&self) -> Self {
528 match self {
529 Self::Compound(v) => Self::Compound(v.clone_as_optional()),
530 _ => self.clone(),
531 }
532 }
533
534 pub fn equals(left: &Self, right: &Self) -> Option<bool> {
539 match (left, right) {
540 (Value::None, Value::None) => Some(true),
541 (Value::None, _) | (_, Value::None) => Some(false),
542 (Value::Primitive(left), Value::Primitive(right)) => {
543 Some(PrimitiveValue::compare(left, right)? == Ordering::Equal)
544 }
545 (Value::Compound(left), Value::Compound(right)) => CompoundValue::equals(left, right),
546 _ => None,
547 }
548 }
549}
550
551impl fmt::Display for Value {
552 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553 match self {
554 Self::None => write!(f, "None"),
555 Self::Primitive(v) => v.fmt(f),
556 Self::Compound(v) => v.fmt(f),
557 Self::Task(_) => write!(f, "task"),
558 Self::Hints(v) => v.fmt(f),
559 Self::Input(v) => v.fmt(f),
560 Self::Output(v) => v.fmt(f),
561 Self::Call(c) => c.fmt(f),
562 }
563 }
564}
565
566impl Coercible for Value {
567 fn coerce(&self, target: &Type) -> Result<Self> {
568 if target.is_union() || target.is_none() || self.ty().eq(target) {
569 return Ok(self.clone());
570 }
571
572 match self {
573 Self::None => {
574 if target.is_optional() {
575 Ok(Self::None)
576 } else {
577 bail!("cannot coerce `None` to non-optional type `{target}`");
578 }
579 }
580 Self::Primitive(v) => v.coerce(target).map(Self::Primitive),
581 Self::Compound(v) => v.coerce(target).map(Self::Compound),
582 Self::Task(_) => {
583 if matches!(target, Type::Task) {
584 return Ok(self.clone());
585 }
586
587 bail!("task variables cannot be coerced to any other type");
588 }
589 Self::Hints(_) => {
590 if matches!(target, Type::Hints) {
591 return Ok(self.clone());
592 }
593
594 bail!("hints values cannot be coerced to any other type");
595 }
596 Self::Input(_) => {
597 if matches!(target, Type::Input) {
598 return Ok(self.clone());
599 }
600
601 bail!("input values cannot be coerced to any other type");
602 }
603 Self::Output(_) => {
604 if matches!(target, Type::Output) {
605 return Ok(self.clone());
606 }
607
608 bail!("output values cannot be coerced to any other type");
609 }
610 Self::Call(_) => {
611 bail!("call values cannot be coerced to any other type");
612 }
613 }
614 }
615}
616
617impl From<bool> for Value {
618 fn from(value: bool) -> Self {
619 Self::Primitive(value.into())
620 }
621}
622
623impl From<i64> for Value {
624 fn from(value: i64) -> Self {
625 Self::Primitive(value.into())
626 }
627}
628
629impl TryFrom<u64> for Value {
630 type Error = std::num::TryFromIntError;
631
632 fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
633 let value: i64 = value.try_into()?;
634 Ok(value.into())
635 }
636}
637
638impl From<f64> for Value {
639 fn from(value: f64) -> Self {
640 Self::Primitive(value.into())
641 }
642}
643
644impl From<String> for Value {
645 fn from(value: String) -> Self {
646 Self::Primitive(value.into())
647 }
648}
649
650impl From<PrimitiveValue> for Value {
651 fn from(value: PrimitiveValue) -> Self {
652 Self::Primitive(value)
653 }
654}
655
656impl From<Option<PrimitiveValue>> for Value {
657 fn from(value: Option<PrimitiveValue>) -> Self {
658 match value {
659 Some(v) => v.into(),
660 None => Self::None,
661 }
662 }
663}
664
665impl From<CompoundValue> for Value {
666 fn from(value: CompoundValue) -> Self {
667 Self::Compound(value)
668 }
669}
670
671impl From<Pair> for Value {
672 fn from(value: Pair) -> Self {
673 Self::Compound(value.into())
674 }
675}
676
677impl From<Array> for Value {
678 fn from(value: Array) -> Self {
679 Self::Compound(value.into())
680 }
681}
682
683impl From<Map> for Value {
684 fn from(value: Map) -> Self {
685 Self::Compound(value.into())
686 }
687}
688
689impl From<Object> for Value {
690 fn from(value: Object) -> Self {
691 Self::Compound(value.into())
692 }
693}
694
695impl From<Struct> for Value {
696 fn from(value: Struct) -> Self {
697 Self::Compound(value.into())
698 }
699}
700
701impl From<TaskValue> for Value {
702 fn from(value: TaskValue) -> Self {
703 Self::Task(value)
704 }
705}
706
707impl From<HintsValue> for Value {
708 fn from(value: HintsValue) -> Self {
709 Self::Hints(value)
710 }
711}
712
713impl From<CallValue> for Value {
714 fn from(value: CallValue) -> Self {
715 Self::Call(value)
716 }
717}
718
719impl serde::Serialize for Value {
720 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
721 where
722 S: serde::Serializer,
723 {
724 use serde::ser::Error;
725
726 match self {
727 Self::None => serializer.serialize_none(),
728 Self::Primitive(v) => v.serialize(serializer),
729 Self::Compound(v) => v.serialize(serializer),
730 Self::Task(_) | Self::Hints(_) | Self::Input(_) | Self::Output(_) | Self::Call(_) => {
731 Err(S::Error::custom("value cannot be serialized"))
732 }
733 }
734 }
735}
736
737impl<'de> serde::Deserialize<'de> for Value {
738 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
739 where
740 D: serde::Deserializer<'de>,
741 {
742 use serde::Deserialize as _;
743
744 struct Deserialize;
746
747 impl<'de> serde::de::DeserializeSeed<'de> for Deserialize {
748 type Value = Value;
749
750 fn deserialize<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
751 where
752 D: serde::Deserializer<'de>,
753 {
754 deserializer.deserialize_any(Visitor)
755 }
756 }
757
758 struct Visitor;
760
761 impl<'de> serde::de::Visitor<'de> for Visitor {
762 type Value = Value;
763
764 fn visit_unit<E>(self) -> std::result::Result<Self::Value, E>
765 where
766 E: serde::de::Error,
767 {
768 Ok(Value::None)
769 }
770
771 fn visit_none<E>(self) -> std::result::Result<Self::Value, E>
772 where
773 E: serde::de::Error,
774 {
775 Ok(Value::None)
776 }
777
778 fn visit_some<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
779 where
780 D: serde::Deserializer<'de>,
781 {
782 Value::deserialize(deserializer)
783 }
784
785 fn visit_bool<E>(self, v: bool) -> std::result::Result<Self::Value, E>
786 where
787 E: serde::de::Error,
788 {
789 Ok(Value::Primitive(PrimitiveValue::Boolean(v)))
790 }
791
792 fn visit_i64<E>(self, v: i64) -> std::result::Result<Self::Value, E>
793 where
794 E: serde::de::Error,
795 {
796 Ok(Value::Primitive(PrimitiveValue::Integer(v)))
797 }
798
799 fn visit_u64<E>(self, v: u64) -> std::result::Result<Self::Value, E>
800 where
801 E: serde::de::Error,
802 {
803 Ok(Value::Primitive(PrimitiveValue::Integer(
804 v.try_into().map_err(|_| {
805 E::custom("integer not in range for a 64-bit signed integer")
806 })?,
807 )))
808 }
809
810 fn visit_f64<E>(self, v: f64) -> std::result::Result<Self::Value, E>
811 where
812 E: serde::de::Error,
813 {
814 Ok(Value::Primitive(PrimitiveValue::Float(v.into())))
815 }
816
817 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
818 where
819 E: serde::de::Error,
820 {
821 Ok(Value::Primitive(PrimitiveValue::new_string(v)))
822 }
823
824 fn visit_string<E>(self, v: String) -> std::result::Result<Self::Value, E>
825 where
826 E: serde::de::Error,
827 {
828 Ok(Value::Primitive(PrimitiveValue::new_string(v)))
829 }
830
831 fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
832 where
833 A: serde::de::SeqAccess<'de>,
834 {
835 use serde::de::Error;
836
837 let mut elements = Vec::new();
838 while let Some(v) = seq.next_element_seed(Deserialize)? {
839 elements.push(v);
840 }
841
842 let element_ty = elements
843 .iter()
844 .try_fold(None, |mut ty, element| {
845 let element_ty = element.ty();
846 let ty = ty.get_or_insert(element_ty.clone());
847 ty.common_type(&element_ty).map(Some).ok_or_else(|| {
848 A::Error::custom(format!(
849 "a common element type does not exist between `{ty}` and \
850 `{element_ty}`"
851 ))
852 })
853 })?
854 .unwrap_or(Type::Union);
855
856 let ty: Type = ArrayType::new(element_ty).into();
857 Ok(Array::new(ty.clone(), elements)
858 .map_err(|e| A::Error::custom(format!("cannot coerce value to `{ty}`: {e:#}")))?
859 .into())
860 }
861
862 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
863 where
864 A: serde::de::MapAccess<'de>,
865 {
866 use serde::de::Error;
867
868 let mut members = IndexMap::new();
869 while let Some(key) = map.next_key::<String>()? {
870 if !is_ident(&key) {
871 return Err(A::Error::custom(format!(
872 "object key `{key}` is not a valid WDL identifier"
873 )));
874 }
875
876 members.insert(key, map.next_value_seed(Deserialize)?);
877 }
878
879 Ok(Value::Compound(CompoundValue::Object(members.into())))
880 }
881
882 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
883 write!(f, "a WDL value")
884 }
885 }
886
887 deserializer.deserialize_any(Visitor)
888 }
889}
890
891#[derive(Debug, Clone)]
895pub enum PrimitiveValue {
896 Boolean(bool),
898 Integer(i64),
900 Float(OrderedFloat<f64>),
902 String(Arc<String>),
904 File(Arc<String>),
906 Directory(Arc<String>),
908}
909
910impl PrimitiveValue {
911 pub fn new_string(s: impl Into<String>) -> Self {
913 Self::String(Arc::new(s.into()))
914 }
915
916 pub fn new_file(s: impl Into<String>) -> Self {
918 Self::File(Arc::new(s.into()))
919 }
920
921 pub fn new_directory(s: impl Into<String>) -> Self {
923 Self::Directory(Arc::new(s.into()))
924 }
925
926 pub fn ty(&self) -> Type {
928 match self {
929 Self::Boolean(_) => PrimitiveType::Boolean.into(),
930 Self::Integer(_) => PrimitiveType::Integer.into(),
931 Self::Float(_) => PrimitiveType::Float.into(),
932 Self::String(_) => PrimitiveType::String.into(),
933 Self::File(_) => PrimitiveType::File.into(),
934 Self::Directory(_) => PrimitiveType::Directory.into(),
935 }
936 }
937
938 pub fn as_boolean(&self) -> Option<bool> {
942 match self {
943 Self::Boolean(v) => Some(*v),
944 _ => None,
945 }
946 }
947
948 pub fn unwrap_boolean(self) -> bool {
954 match self {
955 Self::Boolean(v) => v,
956 _ => panic!("value is not a boolean"),
957 }
958 }
959
960 pub fn as_integer(&self) -> Option<i64> {
964 match self {
965 Self::Integer(v) => Some(*v),
966 _ => None,
967 }
968 }
969
970 pub fn unwrap_integer(self) -> i64 {
976 match self {
977 Self::Integer(v) => v,
978 _ => panic!("value is not an integer"),
979 }
980 }
981
982 pub fn as_float(&self) -> Option<f64> {
986 match self {
987 Self::Float(v) => Some((*v).into()),
988 _ => None,
989 }
990 }
991
992 pub fn unwrap_float(self) -> f64 {
998 match self {
999 Self::Float(v) => v.into(),
1000 _ => panic!("value is not a float"),
1001 }
1002 }
1003
1004 pub fn as_string(&self) -> Option<&Arc<String>> {
1008 match self {
1009 Self::String(s) => Some(s),
1010 _ => None,
1011 }
1012 }
1013
1014 pub fn unwrap_string(self) -> Arc<String> {
1020 match self {
1021 Self::String(s) => s,
1022 _ => panic!("value is not a string"),
1023 }
1024 }
1025
1026 pub fn as_file(&self) -> Option<&Arc<String>> {
1030 match self {
1031 Self::File(s) => Some(s),
1032 _ => None,
1033 }
1034 }
1035
1036 pub fn unwrap_file(self) -> Arc<String> {
1042 match self {
1043 Self::File(s) => s,
1044 _ => panic!("value is not a file"),
1045 }
1046 }
1047
1048 pub fn as_directory(&self) -> Option<&Arc<String>> {
1052 match self {
1053 Self::Directory(s) => Some(s),
1054 _ => None,
1055 }
1056 }
1057
1058 pub fn unwrap_directory(self) -> Arc<String> {
1064 match self {
1065 Self::Directory(s) => s,
1066 _ => panic!("value is not a directory"),
1067 }
1068 }
1069
1070 pub fn compare(left: &Self, right: &Self) -> Option<Ordering> {
1077 match (left, right) {
1078 (Self::Boolean(left), Self::Boolean(right)) => Some(left.cmp(right)),
1079 (Self::Integer(left), Self::Integer(right)) => Some(left.cmp(right)),
1080 (Self::Integer(left), Self::Float(right)) => {
1081 Some(OrderedFloat(*left as f64).cmp(right))
1082 }
1083 (Self::Float(left), Self::Integer(right)) => {
1084 Some(left.cmp(&OrderedFloat(*right as f64)))
1085 }
1086 (Self::Float(left), Self::Float(right)) => Some(left.cmp(right)),
1087 (Self::String(left), Self::String(right))
1088 | (Self::String(left), Self::File(right))
1089 | (Self::String(left), Self::Directory(right))
1090 | (Self::File(left), Self::File(right))
1091 | (Self::File(left), Self::String(right))
1092 | (Self::Directory(left), Self::Directory(right))
1093 | (Self::Directory(left), Self::String(right)) => Some(left.cmp(right)),
1094 _ => None,
1095 }
1096 }
1097
1098 pub fn raw<'a>(
1105 &'a self,
1106 context: Option<&'a dyn EvaluationContext>,
1107 ) -> impl fmt::Display + use<'a> {
1108 struct Display<'a> {
1110 context: Option<&'a dyn EvaluationContext>,
1112 value: &'a PrimitiveValue,
1114 }
1115
1116 impl fmt::Display for Display<'_> {
1117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1118 match self.value {
1119 PrimitiveValue::Boolean(v) => write!(f, "{v}"),
1120 PrimitiveValue::Integer(v) => write!(f, "{v}"),
1121 PrimitiveValue::Float(v) => write!(f, "{v:.6?}"),
1122 PrimitiveValue::String(v)
1123 | PrimitiveValue::File(v)
1124 | PrimitiveValue::Directory(v) => {
1125 match self.context.and_then(|c| c.translate_path(v)) {
1126 Some(path) => write!(f, "{path}", path = path.display()),
1127 None => {
1128 write!(f, "{v}")
1129 }
1130 }
1131 }
1132 }
1133 }
1134 }
1135
1136 Display {
1137 context,
1138 value: self,
1139 }
1140 }
1141
1142 fn visit_paths(
1146 &self,
1147 optional: bool,
1148 cb: &mut impl FnMut(bool, &PrimitiveValue) -> Result<()>,
1149 ) -> Result<()> {
1150 match self {
1151 Self::File(_) | Self::Directory(_) => cb(optional, self),
1152 _ => Ok(()),
1153 }
1154 }
1155
1156 fn visit_paths_mut(
1163 &mut self,
1164 optional: bool,
1165 cb: &mut impl FnMut(bool, &mut PrimitiveValue) -> Result<bool>,
1166 ) -> Result<bool> {
1167 match self {
1168 Self::File(_) | Self::Directory(_) => cb(optional, self),
1169 _ => Ok(true),
1170 }
1171 }
1172
1173 pub(crate) fn expand_path(&mut self) -> Result<()> {
1175 let path = match self {
1176 PrimitiveValue::File(path) => path,
1177 PrimitiveValue::Directory(path) => path,
1178 _ => unreachable!("only file and directory values can be expanded"),
1179 };
1180
1181 let result = shellexpand::full(path.as_str())
1182 .context("expanding file/directory path using shell rules")?;
1183 *Arc::make_mut(path) = result.to_string();
1184
1185 Ok(())
1186 }
1187
1188 pub(crate) fn join_path_to(&mut self, to: &Path) {
1194 let path = match self {
1195 PrimitiveValue::File(path) => path,
1196 PrimitiveValue::Directory(path) => path,
1197 _ => unreachable!("only file and directory values can be joined to a path"),
1198 };
1199
1200 if path::is_url(path) {
1202 return;
1203 }
1204
1205 if let Ok(s) = to.join(path.as_str()).into_os_string().into_string() {
1207 *Arc::make_mut(path) = s;
1208 }
1209 }
1210
1211 pub(crate) fn ensure_path_exists(&self, optional: bool) -> Result<bool> {
1224 let (path, is_file) = match self {
1225 PrimitiveValue::File(path) => (path, true),
1226 PrimitiveValue::Directory(path) => (path, false),
1227 _ => unreachable!("only file and directory values should be passed to the callback"),
1228 };
1229
1230 if path::is_file_url(path) {
1232 let exists = path::parse_url(path)
1233 .and_then(|url| url.to_file_path().ok())
1234 .map(|p| p.exists())
1235 .unwrap_or(false);
1236 if exists {
1237 return Ok(true);
1238 }
1239
1240 if optional && !exists {
1241 return Ok(false);
1242 }
1243
1244 bail!("path `{path}` does not exist");
1245 } else if path::is_url(path) {
1246 return Ok(true);
1248 }
1249
1250 let path = Path::new(path.as_str());
1252 if is_file && !path.is_file() {
1253 if optional {
1254 return Ok(false);
1255 }
1256
1257 bail!("file `{path}` does not exist", path = path.display());
1258 } else if !is_file && !path.is_dir() {
1259 if optional {
1260 return Ok(false);
1261 }
1262
1263 bail!("directory `{path}` does not exist", path = path.display())
1264 }
1265
1266 Ok(true)
1267 }
1268}
1269
1270impl fmt::Display for PrimitiveValue {
1271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1272 match self {
1273 Self::Boolean(v) => write!(f, "{v}"),
1274 Self::Integer(v) => write!(f, "{v}"),
1275 Self::Float(v) => write!(f, "{v:.6?}"),
1276 Self::String(s) | Self::File(s) | Self::Directory(s) => {
1277 write!(f, "\"{s}\"")
1279 }
1280 }
1281 }
1282}
1283
1284impl PartialEq for PrimitiveValue {
1285 fn eq(&self, other: &Self) -> bool {
1286 Self::compare(self, other) == Some(Ordering::Equal)
1287 }
1288}
1289
1290impl Eq for PrimitiveValue {}
1291
1292impl Hash for PrimitiveValue {
1293 fn hash<H: Hasher>(&self, state: &mut H) {
1294 match self {
1295 Self::Boolean(v) => {
1296 0.hash(state);
1297 v.hash(state);
1298 }
1299 Self::Integer(v) => {
1300 1.hash(state);
1301 v.hash(state);
1302 }
1303 Self::Float(v) => {
1304 1.hash(state);
1307 v.hash(state);
1308 }
1309 Self::String(v) | Self::File(v) | Self::Directory(v) => {
1310 2.hash(state);
1313 v.hash(state);
1314 }
1315 }
1316 }
1317}
1318
1319impl From<bool> for PrimitiveValue {
1320 fn from(value: bool) -> Self {
1321 Self::Boolean(value)
1322 }
1323}
1324
1325impl From<i64> for PrimitiveValue {
1326 fn from(value: i64) -> Self {
1327 Self::Integer(value)
1328 }
1329}
1330
1331impl From<f64> for PrimitiveValue {
1332 fn from(value: f64) -> Self {
1333 Self::Float(value.into())
1334 }
1335}
1336
1337impl From<String> for PrimitiveValue {
1338 fn from(value: String) -> Self {
1339 Self::String(value.into())
1340 }
1341}
1342
1343impl Coercible for PrimitiveValue {
1344 fn coerce(&self, target: &Type) -> Result<Self> {
1345 if target.is_union() || target.is_none() || self.ty().eq(target) {
1346 return Ok(self.clone());
1347 }
1348
1349 match self {
1350 Self::Boolean(v) => {
1351 target
1352 .as_primitive()
1353 .and_then(|ty| match ty {
1354 PrimitiveType::Boolean => Some(Self::Boolean(*v)),
1356 _ => None,
1357 })
1358 .with_context(|| format!("cannot coerce type `Boolean` to type `{target}`"))
1359 }
1360 Self::Integer(v) => {
1361 target
1362 .as_primitive()
1363 .and_then(|ty| match ty {
1364 PrimitiveType::Integer => Some(Self::Integer(*v)),
1366 PrimitiveType::Float => Some(Self::Float((*v as f64).into())),
1368 _ => None,
1369 })
1370 .with_context(|| format!("cannot coerce type `Int` to type `{target}`"))
1371 }
1372 Self::Float(v) => {
1373 target
1374 .as_primitive()
1375 .and_then(|ty| match ty {
1376 PrimitiveType::Float => Some(Self::Float(*v)),
1378 _ => None,
1379 })
1380 .with_context(|| format!("cannot coerce type `Float` to type `{target}`"))
1381 }
1382 Self::String(s) => {
1383 target
1384 .as_primitive()
1385 .and_then(|ty| match ty {
1386 PrimitiveType::String => Some(Self::String(s.clone())),
1388 PrimitiveType::File => Some(Self::File(s.clone())),
1390 PrimitiveType::Directory => Some(Self::Directory(s.clone())),
1392 _ => None,
1393 })
1394 .with_context(|| format!("cannot coerce type `String` to type `{target}`"))
1395 }
1396 Self::File(s) => {
1397 target
1398 .as_primitive()
1399 .and_then(|ty| match ty {
1400 PrimitiveType::File => Some(Self::File(s.clone())),
1402 PrimitiveType::String => Some(Self::String(s.clone())),
1404 _ => None,
1405 })
1406 .with_context(|| format!("cannot coerce type `File` to type `{target}`"))
1407 }
1408 Self::Directory(s) => {
1409 target
1410 .as_primitive()
1411 .and_then(|ty| match ty {
1412 PrimitiveType::Directory => Some(Self::Directory(s.clone())),
1414 PrimitiveType::String => Some(Self::String(s.clone())),
1416 _ => None,
1417 })
1418 .with_context(|| format!("cannot coerce type `Directory` to type `{target}`"))
1419 }
1420 }
1421 }
1422}
1423
1424impl serde::Serialize for PrimitiveValue {
1425 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1426 where
1427 S: serde::Serializer,
1428 {
1429 match self {
1430 Self::Boolean(v) => v.serialize(serializer),
1431 Self::Integer(v) => v.serialize(serializer),
1432 Self::Float(v) => v.serialize(serializer),
1433 Self::String(s) | Self::File(s) | Self::Directory(s) => s.serialize(serializer),
1434 }
1435 }
1436}
1437
1438#[derive(Debug, Clone)]
1442pub struct Pair {
1443 ty: Type,
1445 values: Arc<(Value, Value)>,
1447}
1448
1449impl Pair {
1450 pub fn new(
1459 ty: impl Into<Type>,
1460 left: impl Into<Value>,
1461 right: impl Into<Value>,
1462 ) -> Result<Self> {
1463 let ty = ty.into();
1464 if let Type::Compound(CompoundType::Pair(ty), optional) = ty {
1465 let left = left
1466 .into()
1467 .coerce(ty.left_type())
1468 .context("failed to coerce pair's left value")?;
1469 let right = right
1470 .into()
1471 .coerce(ty.right_type())
1472 .context("failed to coerce pair's right value")?;
1473 return Ok(Self::new_unchecked(
1474 Type::Compound(CompoundType::Pair(ty), optional),
1475 left,
1476 right,
1477 ));
1478 }
1479
1480 panic!("type `{ty}` is not a pair type");
1481 }
1482
1483 pub(crate) fn new_unchecked(ty: Type, left: Value, right: Value) -> Self {
1486 assert!(ty.as_pair().is_some());
1487 Self {
1488 ty,
1489 values: Arc::new((left, right)),
1490 }
1491 }
1492
1493 pub fn ty(&self) -> Type {
1495 self.ty.clone()
1496 }
1497
1498 pub fn left(&self) -> &Value {
1500 &self.values.0
1501 }
1502
1503 pub fn right(&self) -> &Value {
1505 &self.values.1
1506 }
1507}
1508
1509impl fmt::Display for Pair {
1510 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1511 write!(
1512 f,
1513 "({left}, {right})",
1514 left = self.values.0,
1515 right = self.values.1
1516 )
1517 }
1518}
1519
1520#[derive(Debug, Clone)]
1524pub struct Array {
1525 ty: Type,
1527 elements: Option<Arc<Vec<Value>>>,
1531}
1532
1533impl Array {
1534 pub fn new<V>(ty: impl Into<Type>, elements: impl IntoIterator<Item = V>) -> Result<Self>
1543 where
1544 V: Into<Value>,
1545 {
1546 let ty = ty.into();
1547 if let Type::Compound(CompoundType::Array(ty), optional) = ty {
1548 let element_type = ty.element_type();
1549 let elements = elements
1550 .into_iter()
1551 .enumerate()
1552 .map(|(i, v)| {
1553 let v = v.into();
1554 v.coerce(element_type)
1555 .with_context(|| format!("failed to coerce array element at index {i}"))
1556 })
1557 .collect::<Result<Vec<_>>>()?;
1558
1559 return Ok(Self::new_unchecked(
1560 Type::Compound(CompoundType::Array(ty), optional),
1561 elements,
1562 ));
1563 }
1564
1565 panic!("type `{ty}` is not an array type");
1566 }
1567
1568 pub(crate) fn new_unchecked(ty: Type, elements: Vec<Value>) -> Self {
1571 assert!(ty.as_array().is_some());
1572 Self {
1573 ty,
1574 elements: if elements.is_empty() {
1575 None
1576 } else {
1577 Some(Arc::new(elements))
1578 },
1579 }
1580 }
1581
1582 pub fn ty(&self) -> Type {
1584 self.ty.clone()
1585 }
1586
1587 pub fn as_slice(&self) -> &[Value] {
1589 self.elements.as_ref().map(|v| v.as_slice()).unwrap_or(&[])
1590 }
1591
1592 pub fn len(&self) -> usize {
1594 self.elements.as_ref().map(|v| v.len()).unwrap_or(0)
1595 }
1596
1597 pub fn is_empty(&self) -> bool {
1599 self.len() == 0
1600 }
1601}
1602
1603impl fmt::Display for Array {
1604 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1605 write!(f, "[")?;
1606
1607 if let Some(elements) = &self.elements {
1608 for (i, element) in elements.iter().enumerate() {
1609 if i > 0 {
1610 write!(f, ", ")?;
1611 }
1612
1613 write!(f, "{element}")?;
1614 }
1615 }
1616
1617 write!(f, "]")
1618 }
1619}
1620
1621#[derive(Debug, Clone)]
1625pub struct Map {
1626 ty: Type,
1628 elements: Option<Arc<IndexMap<Option<PrimitiveValue>, Value>>>,
1632}
1633
1634impl Map {
1635 pub fn new<K, V>(
1644 ty: impl Into<Type>,
1645 elements: impl IntoIterator<Item = (K, V)>,
1646 ) -> Result<Self>
1647 where
1648 K: Into<Value>,
1649 V: Into<Value>,
1650 {
1651 let ty = ty.into();
1652 if let Type::Compound(CompoundType::Map(ty), optional) = ty {
1653 let key_type = ty.key_type();
1654 let value_type = ty.value_type();
1655
1656 let elements = elements
1657 .into_iter()
1658 .enumerate()
1659 .map(|(i, (k, v))| {
1660 let k = k.into();
1661 let v = v.into();
1662 Ok((
1663 if k.is_none() {
1664 None
1665 } else {
1666 match k.coerce(key_type).with_context(|| {
1667 format!("failed to coerce map key for element at index {i}")
1668 })? {
1669 Value::None => None,
1670 Value::Primitive(v) => Some(v),
1671 _ => {
1672 bail!("not all key values are primitive")
1673 }
1674 }
1675 },
1676 v.coerce(value_type).with_context(|| {
1677 format!("failed to coerce map value for element at index {i}")
1678 })?,
1679 ))
1680 })
1681 .collect::<Result<_>>()?;
1682
1683 return Ok(Self::new_unchecked(
1684 Type::Compound(CompoundType::Map(ty), optional),
1685 elements,
1686 ));
1687 }
1688
1689 panic!("type `{ty}` is not a map type");
1690 }
1691
1692 pub(crate) fn new_unchecked(
1695 ty: Type,
1696 elements: IndexMap<Option<PrimitiveValue>, Value>,
1697 ) -> Self {
1698 assert!(ty.as_map().is_some());
1699 Self {
1700 ty,
1701 elements: if elements.is_empty() {
1702 None
1703 } else {
1704 Some(Arc::new(elements))
1705 },
1706 }
1707 }
1708
1709 pub fn ty(&self) -> Type {
1711 self.ty.clone()
1712 }
1713
1714 pub fn iter(&self) -> impl Iterator<Item = (&Option<PrimitiveValue>, &Value)> {
1716 self.elements
1717 .as_ref()
1718 .map(|m| Either::Left(m.iter()))
1719 .unwrap_or(Either::Right(std::iter::empty()))
1720 }
1721
1722 pub fn keys(&self) -> impl Iterator<Item = &Option<PrimitiveValue>> {
1724 self.elements
1725 .as_ref()
1726 .map(|m| Either::Left(m.keys()))
1727 .unwrap_or(Either::Right(std::iter::empty()))
1728 }
1729
1730 pub fn values(&self) -> impl Iterator<Item = &Value> {
1732 self.elements
1733 .as_ref()
1734 .map(|m| Either::Left(m.values()))
1735 .unwrap_or(Either::Right(std::iter::empty()))
1736 }
1737
1738 pub fn contains_key(&self, key: &Option<PrimitiveValue>) -> bool {
1740 self.elements
1741 .as_ref()
1742 .map(|m| m.contains_key(key))
1743 .unwrap_or(false)
1744 }
1745
1746 pub fn get(&self, key: &Option<PrimitiveValue>) -> Option<&Value> {
1748 self.elements.as_ref().and_then(|m| m.get(key))
1749 }
1750
1751 pub fn len(&self) -> usize {
1753 self.elements.as_ref().map(|m| m.len()).unwrap_or(0)
1754 }
1755
1756 pub fn is_empty(&self) -> bool {
1758 self.len() == 0
1759 }
1760}
1761
1762impl fmt::Display for Map {
1763 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1764 write!(f, "{{")?;
1765
1766 for (i, (k, v)) in self.iter().enumerate() {
1767 if i > 0 {
1768 write!(f, ", ")?;
1769 }
1770
1771 match k {
1772 Some(k) => write!(f, "{k}: {v}")?,
1773 None => write!(f, "None: {v}")?,
1774 }
1775 }
1776
1777 write!(f, "}}")
1778 }
1779}
1780
1781#[derive(Debug, Clone)]
1785pub struct Object {
1786 pub(crate) members: Option<Arc<IndexMap<String, Value>>>,
1790}
1791
1792impl Object {
1793 pub fn new<S, V>(items: impl IntoIterator<Item = (S, V)>) -> Self
1795 where
1796 S: Into<String>,
1797 V: Into<Value>,
1798 {
1799 items
1800 .into_iter()
1801 .map(|(n, v)| {
1802 let n = n.into();
1803 let v = v.into();
1804 (n, v)
1805 })
1806 .collect::<IndexMap<_, _>>()
1807 .into()
1808 }
1809
1810 pub fn empty() -> Self {
1812 IndexMap::default().into()
1813 }
1814
1815 pub fn from_v1_metadata<N: TreeNode>(
1817 items: impl Iterator<Item = v1::MetadataObjectItem<N>>,
1818 ) -> Self {
1819 items
1820 .map(|i| {
1821 (
1822 i.name().text().to_string(),
1823 Value::from_v1_metadata(&i.value()),
1824 )
1825 })
1826 .collect::<IndexMap<_, _>>()
1827 .into()
1828 }
1829
1830 pub fn ty(&self) -> Type {
1832 Type::Object
1833 }
1834
1835 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
1837 self.members
1838 .as_ref()
1839 .map(|m| Either::Left(m.iter().map(|(k, v)| (k.as_str(), v))))
1840 .unwrap_or(Either::Right(std::iter::empty()))
1841 }
1842
1843 pub fn keys(&self) -> impl Iterator<Item = &str> {
1845 self.members
1846 .as_ref()
1847 .map(|m| Either::Left(m.keys().map(|k| k.as_str())))
1848 .unwrap_or(Either::Right(std::iter::empty()))
1849 }
1850
1851 pub fn values(&self) -> impl Iterator<Item = &Value> {
1853 self.members
1854 .as_ref()
1855 .map(|m| Either::Left(m.values()))
1856 .unwrap_or(Either::Right(std::iter::empty()))
1857 }
1858
1859 pub fn contains_key(&self, key: &str) -> bool {
1861 self.members
1862 .as_ref()
1863 .map(|m| m.contains_key(key))
1864 .unwrap_or(false)
1865 }
1866
1867 pub fn get(&self, key: &str) -> Option<&Value> {
1869 self.members.as_ref().and_then(|m| m.get(key))
1870 }
1871
1872 pub fn len(&self) -> usize {
1874 self.members.as_ref().map(|m| m.len()).unwrap_or(0)
1875 }
1876
1877 pub fn is_empty(&self) -> bool {
1879 self.len() == 0
1880 }
1881}
1882
1883impl fmt::Display for Object {
1884 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1885 write!(f, "object {{")?;
1886
1887 for (i, (k, v)) in self.iter().enumerate() {
1888 if i > 0 {
1889 write!(f, ", ")?;
1890 }
1891
1892 write!(f, "{k}: {v}")?;
1893 }
1894
1895 write!(f, "}}")
1896 }
1897}
1898
1899impl From<IndexMap<String, Value>> for Object {
1900 fn from(members: IndexMap<String, Value>) -> Self {
1901 Self {
1902 members: if members.is_empty() {
1903 None
1904 } else {
1905 Some(Arc::new(members))
1906 },
1907 }
1908 }
1909}
1910
1911#[derive(Debug, Clone)]
1915pub struct Struct {
1916 ty: Type,
1918 name: Arc<String>,
1920 pub(crate) members: Arc<IndexMap<String, Value>>,
1922}
1923
1924impl Struct {
1925 pub fn new<S, V>(ty: impl Into<Type>, members: impl IntoIterator<Item = (S, V)>) -> Result<Self>
1934 where
1935 S: Into<String>,
1936 V: Into<Value>,
1937 {
1938 let ty = ty.into();
1939 if let Type::Compound(CompoundType::Struct(ty), optional) = ty {
1940 let mut members = members
1941 .into_iter()
1942 .map(|(n, v)| {
1943 let n = n.into();
1944 let v = v.into();
1945 let v = v
1946 .coerce(ty.members().get(&n).ok_or_else(|| {
1947 anyhow!("struct does not contain a member named `{n}`")
1948 })?)
1949 .with_context(|| format!("failed to coerce struct member `{n}`"))?;
1950 Ok((n, v))
1951 })
1952 .collect::<Result<IndexMap<_, _>>>()?;
1953
1954 for (name, ty) in ty.members().iter() {
1955 if ty.is_optional() {
1957 if !members.contains_key(name) {
1958 members.insert(name.clone(), Value::None);
1959 }
1960 } else {
1961 if !members.contains_key(name) {
1963 bail!("missing a value for struct member `{name}`");
1964 }
1965 }
1966 }
1967
1968 let name = ty.name().to_string();
1969 return Ok(Self {
1970 ty: Type::Compound(CompoundType::Struct(ty), optional),
1971 name: Arc::new(name),
1972 members: Arc::new(members),
1973 });
1974 }
1975
1976 panic!("type `{ty}` is not a struct type");
1977 }
1978
1979 pub(crate) fn new_unchecked(
1982 ty: Type,
1983 name: Arc<String>,
1984 members: Arc<IndexMap<String, Value>>,
1985 ) -> Self {
1986 assert!(ty.as_struct().is_some());
1987 Self { ty, name, members }
1988 }
1989
1990 pub fn ty(&self) -> Type {
1992 self.ty.clone()
1993 }
1994
1995 pub fn name(&self) -> &Arc<String> {
1997 &self.name
1998 }
1999
2000 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
2002 self.members.iter().map(|(k, v)| (k.as_str(), v))
2003 }
2004
2005 pub fn keys(&self) -> impl Iterator<Item = &str> {
2007 self.members.keys().map(|k| k.as_str())
2008 }
2009
2010 pub fn values(&self) -> impl Iterator<Item = &Value> {
2012 self.members.values()
2013 }
2014
2015 pub fn contains_key(&self, key: &str) -> bool {
2017 self.members.contains_key(key)
2018 }
2019
2020 pub fn get(&self, key: &str) -> Option<&Value> {
2022 self.members.get(key)
2023 }
2024}
2025
2026impl fmt::Display for Struct {
2027 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2028 write!(f, "{name} {{", name = self.name)?;
2029
2030 for (i, (k, v)) in self.members.iter().enumerate() {
2031 if i > 0 {
2032 write!(f, ", ")?;
2033 }
2034
2035 write!(f, "{k}: {v}")?;
2036 }
2037
2038 write!(f, "}}")
2039 }
2040}
2041
2042#[derive(Debug, Clone)]
2046pub enum CompoundValue {
2047 Pair(Pair),
2049 Array(Array),
2051 Map(Map),
2053 Object(Object),
2055 Struct(Struct),
2057}
2058
2059impl CompoundValue {
2060 pub fn ty(&self) -> Type {
2062 match self {
2063 CompoundValue::Pair(v) => v.ty(),
2064 CompoundValue::Array(v) => v.ty(),
2065 CompoundValue::Map(v) => v.ty(),
2066 CompoundValue::Object(v) => v.ty(),
2067 CompoundValue::Struct(v) => v.ty(),
2068 }
2069 }
2070
2071 pub fn as_pair(&self) -> Option<&Pair> {
2075 match self {
2076 Self::Pair(v) => Some(v),
2077 _ => None,
2078 }
2079 }
2080
2081 pub fn unwrap_pair(self) -> Pair {
2087 match self {
2088 Self::Pair(v) => v,
2089 _ => panic!("value is not a pair"),
2090 }
2091 }
2092
2093 pub fn as_array(&self) -> Option<&Array> {
2097 match self {
2098 Self::Array(v) => Some(v),
2099 _ => None,
2100 }
2101 }
2102
2103 pub fn unwrap_array(self) -> Array {
2109 match self {
2110 Self::Array(v) => v,
2111 _ => panic!("value is not an array"),
2112 }
2113 }
2114
2115 pub fn as_map(&self) -> Option<&Map> {
2119 match self {
2120 Self::Map(v) => Some(v),
2121 _ => None,
2122 }
2123 }
2124
2125 pub fn unwrap_map(self) -> Map {
2131 match self {
2132 Self::Map(v) => v,
2133 _ => panic!("value is not a map"),
2134 }
2135 }
2136
2137 pub fn as_object(&self) -> Option<&Object> {
2141 match self {
2142 Self::Object(v) => Some(v),
2143 _ => None,
2144 }
2145 }
2146
2147 pub fn unwrap_object(self) -> Object {
2153 match self {
2154 Self::Object(v) => v,
2155 _ => panic!("value is not an object"),
2156 }
2157 }
2158
2159 pub fn as_struct(&self) -> Option<&Struct> {
2163 match self {
2164 Self::Struct(v) => Some(v),
2165 _ => None,
2166 }
2167 }
2168
2169 pub fn unwrap_struct(self) -> Struct {
2175 match self {
2176 Self::Struct(v) => v,
2177 _ => panic!("value is not a struct"),
2178 }
2179 }
2180
2181 pub fn equals(left: &Self, right: &Self) -> Option<bool> {
2187 if left.ty() != right.ty() {
2190 return None;
2191 }
2192
2193 match (left, right) {
2194 (Self::Pair(left), Self::Pair(right)) => Some(
2195 Value::equals(left.left(), right.left())?
2196 && Value::equals(left.right(), right.right())?,
2197 ),
2198 (CompoundValue::Array(left), CompoundValue::Array(right)) => Some(
2199 left.len() == right.len()
2200 && left
2201 .as_slice()
2202 .iter()
2203 .zip(right.as_slice())
2204 .all(|(l, r)| Value::equals(l, r).unwrap_or(false)),
2205 ),
2206 (CompoundValue::Map(left), CompoundValue::Map(right)) => Some(
2207 left.len() == right.len()
2208 && left.iter().zip(right.iter()).all(|((lk, lv), (rk, rv))| {
2210 match (lk, rk) {
2211 (None, None) => {},
2212 (Some(lk), Some(rk)) if lk == rk => {},
2213 _ => return false
2214 }
2215
2216 Value::equals(lv, rv).unwrap_or(false)
2217 }),
2218 ),
2219 (CompoundValue::Object(left), CompoundValue::Object(right)) => Some(
2220 left.len() == right.len()
2221 && left.iter().all(|(k, left)| match right.get(k) {
2222 Some(right) => Value::equals(left, right).unwrap_or(false),
2223 None => false,
2224 }),
2225 ),
2226 (
2227 CompoundValue::Struct(Struct { members: left, .. }),
2228 CompoundValue::Struct(Struct { members: right, .. }),
2229 ) => Some(
2230 left.len() == right.len()
2231 && left.iter().all(|(k, left)| match right.get(k) {
2232 Some(right) => Value::equals(left, right).unwrap_or(false),
2233 None => false,
2234 }),
2235 ),
2236 _ => None,
2237 }
2238 }
2239
2240 fn visit_paths(&self, cb: &mut impl FnMut(bool, &PrimitiveValue) -> Result<()>) -> Result<()> {
2244 match self {
2245 Self::Pair(pair) => {
2246 let ty = pair.ty.as_pair().expect("should be a pair type");
2247 pair.left().visit_paths(ty.left_type().is_optional(), cb)?;
2248 pair.right()
2249 .visit_paths(ty.right_type().is_optional(), cb)?;
2250 }
2251 Self::Array(array) => {
2252 let ty = array.ty.as_array().expect("should be an array type");
2253 let optional = ty.element_type().is_optional();
2254 if let Some(elements) = &array.elements {
2255 for v in elements.iter() {
2256 v.visit_paths(optional, cb)?;
2257 }
2258 }
2259 }
2260 Self::Map(map) => {
2261 let ty = map.ty.as_map().expect("should be a map type");
2262 let (key_optional, value_optional) =
2263 (ty.key_type().is_optional(), ty.value_type().is_optional());
2264 if let Some(elements) = &map.elements {
2265 for (k, v) in elements.iter() {
2266 if let Some(k) = k {
2267 k.visit_paths(key_optional, cb)?;
2268 }
2269
2270 v.visit_paths(value_optional, cb)?;
2271 }
2272 }
2273 }
2274 Self::Object(object) => {
2275 if let Some(members) = &object.members {
2276 for v in members.values() {
2277 v.visit_paths(false, cb)?;
2278 }
2279 }
2280 }
2281 Self::Struct(s) => {
2282 let ty = s.ty.as_struct().expect("should be a struct type");
2283 for (n, v) in s.members.iter() {
2284 v.visit_paths(ty.members()[n].is_optional(), cb)?;
2285 }
2286 }
2287 }
2288
2289 Ok(())
2290 }
2291
2292 fn visit_paths_mut(
2299 &mut self,
2300 cb: &mut impl FnMut(bool, &mut PrimitiveValue) -> Result<bool>,
2301 ) -> Result<()> {
2302 match self {
2303 Self::Pair(pair) => {
2304 let ty = pair.ty.as_pair().expect("should be a pair type");
2305 let (left_optional, right_optional) =
2306 (ty.left_type().is_optional(), ty.right_type().is_optional());
2307 let values = Arc::make_mut(&mut pair.values);
2308 values.0.visit_paths_mut(left_optional, cb)?;
2309 values.1.visit_paths_mut(right_optional, cb)?;
2310 }
2311 Self::Array(array) => {
2312 let ty = array.ty.as_array().expect("should be an array type");
2313 let optional = ty.element_type().is_optional();
2314 if let Some(elements) = &mut array.elements {
2315 for v in Arc::make_mut(elements) {
2316 v.visit_paths_mut(optional, cb)?;
2317 }
2318 }
2319 }
2320 Self::Map(map) => {
2321 let ty = map.ty.as_map().expect("should be a map type");
2322 let (key_optional, value_optional) =
2323 (ty.key_type().is_optional(), ty.value_type().is_optional());
2324 if let Some(elements) = &mut map.elements {
2325 if elements
2326 .iter()
2327 .find_map(|(k, _)| {
2328 k.as_ref().map(|v| {
2329 matches!(v, PrimitiveValue::File(_) | PrimitiveValue::Directory(_))
2330 })
2331 })
2332 .unwrap_or(false)
2333 {
2334 let elements = Arc::make_mut(elements);
2337 let new = elements
2338 .drain(..)
2339 .map(|(mut k, mut v)| {
2340 if let Some(v) = &mut k {
2341 if !v.visit_paths_mut(key_optional, cb)? {
2342 k = None;
2343 }
2344 }
2345
2346 v.visit_paths_mut(value_optional, cb)?;
2347 Ok((k, v))
2348 })
2349 .collect::<Result<Vec<_>>>()?;
2350 elements.extend(new);
2351 } else {
2352 for v in Arc::make_mut(elements).values_mut() {
2354 v.visit_paths_mut(value_optional, cb)?;
2355 }
2356 }
2357 }
2358 }
2359 Self::Object(object) => {
2360 if let Some(members) = &mut object.members {
2361 for v in Arc::make_mut(members).values_mut() {
2362 v.visit_paths_mut(false, cb)?;
2363 }
2364 }
2365 }
2366 Self::Struct(s) => {
2367 let ty = s.ty.as_struct().expect("should be a struct type");
2368 for (n, v) in Arc::make_mut(&mut s.members).iter_mut() {
2369 v.visit_paths_mut(ty.members()[n].is_optional(), cb)?;
2370 }
2371 }
2372 }
2373
2374 Ok(())
2375 }
2376
2377 fn clone_as_required(&self) -> Self {
2379 match self {
2380 Self::Pair(v) => Self::Pair(Pair {
2381 ty: v.ty.require(),
2382 values: v.values.clone(),
2383 }),
2384 Self::Array(v) => Self::Array(Array {
2385 ty: v.ty.require(),
2386 elements: v.elements.clone(),
2387 }),
2388 Self::Map(v) => Self::Map(Map {
2389 ty: v.ty.require(),
2390 elements: v.elements.clone(),
2391 }),
2392 Self::Object(_) => self.clone(),
2393 Self::Struct(v) => Self::Struct(Struct {
2394 ty: v.ty.require(),
2395 name: v.name.clone(),
2396 members: v.members.clone(),
2397 }),
2398 }
2399 }
2400
2401 fn clone_as_optional(&self) -> Self {
2403 match self {
2404 Self::Pair(v) => Self::Pair(Pair {
2405 ty: v.ty.optional(),
2406 values: v.values.clone(),
2407 }),
2408 Self::Array(v) => Self::Array(Array {
2409 ty: v.ty.optional(),
2410 elements: v.elements.clone(),
2411 }),
2412 Self::Map(v) => Self::Map(Map {
2413 ty: v.ty.optional(),
2414 elements: v.elements.clone(),
2415 }),
2416 Self::Object(_) => self.clone(),
2417 Self::Struct(v) => Self::Struct(Struct {
2418 ty: v.ty.optional(),
2419 name: v.name.clone(),
2420 members: v.members.clone(),
2421 }),
2422 }
2423 }
2424}
2425
2426impl fmt::Display for CompoundValue {
2427 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2428 match self {
2429 Self::Pair(v) => v.fmt(f),
2430 Self::Array(v) => v.fmt(f),
2431 Self::Map(v) => v.fmt(f),
2432 Self::Object(v) => v.fmt(f),
2433 Self::Struct(v) => v.fmt(f),
2434 }
2435 }
2436}
2437
2438impl Coercible for CompoundValue {
2439 fn coerce(&self, target: &Type) -> Result<Self> {
2440 if target.is_union() || target.is_none() || self.ty().eq(target) {
2441 return Ok(self.clone());
2442 }
2443
2444 if let Type::Compound(target_ty, _) = target {
2445 match (self, target_ty) {
2446 (Self::Array(v), CompoundType::Array(target_ty)) => {
2448 if v.is_empty() && target_ty.is_non_empty() {
2451 bail!("cannot coerce empty array value to non-empty array type `{target}`",);
2452 }
2453
2454 return Ok(Self::Array(Array::new(
2455 target.clone(),
2456 v.as_slice().iter().cloned(),
2457 )?));
2458 }
2459 (Self::Map(v), CompoundType::Map(_)) => {
2461 return Ok(Self::Map(Map::new(
2462 target.clone(),
2463 v.iter().map(|(k, v)| {
2464 (k.clone().map(Into::into).unwrap_or(Value::None), v.clone())
2465 }),
2466 )?));
2467 }
2468 (Self::Pair(v), CompoundType::Pair(_)) => {
2470 return Ok(Self::Pair(Pair::new(
2471 target.clone(),
2472 v.values.0.clone(),
2473 v.values.1.clone(),
2474 )?));
2475 }
2476 (Self::Map(v), CompoundType::Struct(target_ty)) => {
2478 let len = v.len();
2479 let expected_len = target_ty.members().len();
2480
2481 if len != expected_len {
2482 bail!(
2483 "cannot coerce a map of {len} element{s1} to struct type `{target}` \
2484 as the struct has {expected_len} member{s2}",
2485 s1 = if len == 1 { "" } else { "s" },
2486 s2 = if expected_len == 1 { "" } else { "s" }
2487 );
2488 }
2489
2490 return Ok(Self::Struct(Struct {
2491 ty: target.clone(),
2492 name: target_ty.name().clone(),
2493 members: Arc::new(
2494 v.iter()
2495 .map(|(k, v)| {
2496 let k: String = k
2497 .as_ref()
2498 .and_then(|k| k.as_string())
2499 .with_context(|| {
2500 format!(
2501 "cannot coerce a map with a non-string key type \
2502 to struct type `{target}`"
2503 )
2504 })?
2505 .to_string();
2506 let ty = target_ty.members().get(&k).with_context(|| {
2507 format!(
2508 "cannot coerce a map with key `{k}` to struct type \
2509 `{target}` as the struct does not contain a member \
2510 with that name"
2511 )
2512 })?;
2513 let v = v.coerce(ty).with_context(|| {
2514 format!("failed to coerce value of map key `{k}")
2515 })?;
2516 Ok((k, v))
2517 })
2518 .collect::<Result<_>>()?,
2519 ),
2520 }));
2521 }
2522 (Self::Struct(Struct { members, .. }), CompoundType::Map(map_ty)) => {
2525 if map_ty.key_type().as_primitive() != Some(PrimitiveType::String) {
2526 bail!(
2527 "cannot coerce a struct or object to type `{target}` as it requires a \
2528 `String` key type"
2529 );
2530 }
2531
2532 let value_ty = map_ty.value_type();
2533 return Ok(Self::Map(Map::new_unchecked(
2534 target.clone(),
2535 members
2536 .iter()
2537 .map(|(n, v)| {
2538 let v = v
2539 .coerce(value_ty)
2540 .with_context(|| format!("failed to coerce member `{n}`"))?;
2541 Ok((PrimitiveValue::new_string(n).into(), v))
2542 })
2543 .collect::<Result<_>>()?,
2544 )));
2545 }
2546 (Self::Object(object), CompoundType::Map(map_ty)) => {
2547 if map_ty.key_type().as_primitive() != Some(PrimitiveType::String) {
2548 bail!(
2549 "cannot coerce a struct or object to type `{target}` as it requires a \
2550 `String` key type",
2551 );
2552 }
2553
2554 let value_ty = map_ty.value_type();
2555 return Ok(Self::Map(Map::new_unchecked(
2556 target.clone(),
2557 object
2558 .iter()
2559 .map(|(n, v)| {
2560 let v = v
2561 .coerce(value_ty)
2562 .with_context(|| format!("failed to coerce member `{n}`"))?;
2563 Ok((PrimitiveValue::new_string(n).into(), v))
2564 })
2565 .collect::<Result<_>>()?,
2566 )));
2567 }
2568 (Self::Object(v), CompoundType::Struct(_)) => {
2570 return Ok(Self::Struct(Struct::new(
2571 target.clone(),
2572 v.iter().map(|(k, v)| (k, v.clone())),
2573 )?));
2574 }
2575 (Self::Struct(v), CompoundType::Struct(struct_ty)) => {
2577 let len = v.members.len();
2578 let expected_len = struct_ty.members().len();
2579
2580 if len != expected_len {
2581 bail!(
2582 "cannot coerce a struct of {len} members{s1} to struct type \
2583 `{target}` as the target struct has {expected_len} member{s2}",
2584 s1 = if len == 1 { "" } else { "s" },
2585 s2 = if expected_len == 1 { "" } else { "s" }
2586 );
2587 }
2588
2589 return Ok(Self::Struct(Struct {
2590 ty: target.clone(),
2591 name: struct_ty.name().clone(),
2592 members: Arc::new(
2593 v.members
2594 .iter()
2595 .map(|(k, v)| {
2596 let ty = struct_ty.members().get(k).ok_or_else(|| {
2597 anyhow!(
2598 "cannot coerce a struct with member `{k}` to struct \
2599 type `{target}` as the target struct does not \
2600 contain a member with that name",
2601 )
2602 })?;
2603 let v = v.coerce(ty).with_context(|| {
2604 format!("failed to coerce member `{k}`")
2605 })?;
2606 Ok((k.clone(), v))
2607 })
2608 .collect::<Result<_>>()?,
2609 ),
2610 }));
2611 }
2612 _ => {}
2613 }
2614 }
2615
2616 if let Type::Object = target {
2617 match self {
2618 Self::Map(v) => {
2620 return Ok(Self::Object(
2621 v.iter()
2622 .map(|(k, v)| {
2623 let k = k
2624 .as_ref()
2625 .and_then(|k| k.as_string())
2626 .context(
2627 "cannot coerce a map with a non-string key type to type \
2628 `Object`",
2629 )?
2630 .to_string();
2631 Ok((k, v.clone()))
2632 })
2633 .collect::<Result<IndexMap<_, _>>>()?
2634 .into(),
2635 ));
2636 }
2637 Self::Struct(v) => {
2639 return Ok(Self::Object(Object {
2640 members: Some(v.members.clone()),
2641 }));
2642 }
2643 _ => {}
2644 };
2645 }
2646
2647 bail!(
2648 "cannot coerce a value of type `{ty}` to type `{target}`",
2649 ty = self.ty()
2650 );
2651 }
2652}
2653
2654impl From<Pair> for CompoundValue {
2655 fn from(value: Pair) -> Self {
2656 Self::Pair(value)
2657 }
2658}
2659
2660impl From<Array> for CompoundValue {
2661 fn from(value: Array) -> Self {
2662 Self::Array(value)
2663 }
2664}
2665
2666impl From<Map> for CompoundValue {
2667 fn from(value: Map) -> Self {
2668 Self::Map(value)
2669 }
2670}
2671
2672impl From<Object> for CompoundValue {
2673 fn from(value: Object) -> Self {
2674 Self::Object(value)
2675 }
2676}
2677
2678impl From<Struct> for CompoundValue {
2679 fn from(value: Struct) -> Self {
2680 Self::Struct(value)
2681 }
2682}
2683
2684impl serde::Serialize for CompoundValue {
2685 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2686 where
2687 S: serde::Serializer,
2688 {
2689 use serde::ser::Error;
2690
2691 match self {
2692 Self::Pair(_) => Err(S::Error::custom("a pair cannot be serialized")),
2693 Self::Array(v) => {
2694 let mut s = serializer.serialize_seq(Some(v.len()))?;
2695 for v in v.as_slice() {
2696 s.serialize_element(v)?;
2697 }
2698
2699 s.end()
2700 }
2701 Self::Map(v) => {
2702 if !v
2703 .ty()
2704 .as_map()
2705 .expect("type should be a map")
2706 .key_type()
2707 .is_coercible_to(&PrimitiveType::String.into())
2708 {
2709 return Err(S::Error::custom(
2710 "only maps with `String` key types may be serialized",
2711 ));
2712 }
2713
2714 let mut s = serializer.serialize_map(Some(v.len()))?;
2715 for (k, v) in v.iter() {
2716 s.serialize_entry(k, v)?;
2717 }
2718
2719 s.end()
2720 }
2721 Self::Object(object) => {
2722 let mut s = serializer.serialize_map(Some(object.len()))?;
2723 for (k, v) in object.iter() {
2724 s.serialize_entry(k, v)?;
2725 }
2726
2727 s.end()
2728 }
2729 Self::Struct(Struct { members, .. }) => {
2730 let mut s = serializer.serialize_map(Some(members.len()))?;
2731 for (k, v) in members.iter() {
2732 s.serialize_entry(k, v)?;
2733 }
2734
2735 s.end()
2736 }
2737 }
2738 }
2739}
2740
2741#[derive(Debug)]
2743struct TaskData {
2744 name: Arc<String>,
2746 id: Arc<String>,
2748 container: Option<Arc<String>>,
2750 cpu: f64,
2752 memory: i64,
2754 gpu: Array,
2759 fpga: Array,
2764 disks: Map,
2771 end_time: Option<i64>,
2775 meta: Object,
2777 parameter_meta: Object,
2779 ext: Object,
2781}
2782
2783#[derive(Debug, Clone)]
2787pub struct TaskValue {
2788 data: Arc<TaskData>,
2790 attempt: i64,
2795 return_code: Option<i64>,
2799}
2800
2801impl TaskValue {
2802 pub(crate) fn new_v1<N: TreeNode>(
2804 name: impl Into<String>,
2805 id: impl Into<String>,
2806 definition: &v1::TaskDefinition<N>,
2807 constraints: TaskExecutionConstraints,
2808 attempt: i64,
2809 ) -> Self {
2810 Self {
2811 data: Arc::new(TaskData {
2812 name: Arc::new(name.into()),
2813 id: Arc::new(id.into()),
2814 container: constraints.container.map(Into::into),
2815 cpu: constraints.cpu,
2816 memory: constraints.memory,
2817 gpu: Array::new_unchecked(
2818 ANALYSIS_STDLIB.array_string_type().clone(),
2819 constraints
2820 .gpu
2821 .into_iter()
2822 .map(|v| PrimitiveValue::new_string(v).into())
2823 .collect(),
2824 ),
2825 fpga: Array::new_unchecked(
2826 ANALYSIS_STDLIB.array_string_type().clone(),
2827 constraints
2828 .fpga
2829 .into_iter()
2830 .map(|v| PrimitiveValue::new_string(v).into())
2831 .collect(),
2832 ),
2833 disks: Map::new_unchecked(
2834 ANALYSIS_STDLIB.map_string_int_type().clone(),
2835 constraints
2836 .disks
2837 .into_iter()
2838 .map(|(k, v)| (Some(PrimitiveValue::new_string(k)), v.into()))
2839 .collect(),
2840 ),
2841 end_time: None,
2842 meta: definition
2843 .metadata()
2844 .map(|s| Object::from_v1_metadata(s.items()))
2845 .unwrap_or_else(Object::empty),
2846 parameter_meta: definition
2847 .parameter_metadata()
2848 .map(|s| Object::from_v1_metadata(s.items()))
2849 .unwrap_or_else(Object::empty),
2850 ext: Object::empty(),
2851 }),
2852 attempt,
2853 return_code: None,
2854 }
2855 }
2856
2857 pub fn name(&self) -> &Arc<String> {
2859 &self.data.name
2860 }
2861
2862 pub fn id(&self) -> &Arc<String> {
2864 &self.data.id
2865 }
2866
2867 pub fn container(&self) -> Option<&Arc<String>> {
2869 self.data.container.as_ref()
2870 }
2871
2872 pub fn cpu(&self) -> f64 {
2874 self.data.cpu
2875 }
2876
2877 pub fn memory(&self) -> i64 {
2879 self.data.memory
2880 }
2881
2882 pub fn gpu(&self) -> &Array {
2887 &self.data.gpu
2888 }
2889
2890 pub fn fpga(&self) -> &Array {
2895 &self.data.fpga
2896 }
2897
2898 pub fn disks(&self) -> &Map {
2905 &self.data.disks
2906 }
2907
2908 pub fn attempt(&self) -> i64 {
2913 self.attempt
2914 }
2915
2916 pub fn end_time(&self) -> Option<i64> {
2920 self.data.end_time
2921 }
2922
2923 pub fn return_code(&self) -> Option<i64> {
2927 self.return_code
2928 }
2929
2930 pub fn meta(&self) -> &Object {
2932 &self.data.meta
2933 }
2934
2935 pub fn parameter_meta(&self) -> &Object {
2937 &self.data.parameter_meta
2938 }
2939
2940 pub fn ext(&self) -> &Object {
2942 &self.data.ext
2943 }
2944
2945 pub(crate) fn set_return_code(&mut self, code: i32) {
2947 self.return_code = Some(code as i64);
2948 }
2949
2950 pub(crate) fn set_attempt(&mut self, attempt: i64) {
2952 self.attempt = attempt;
2953 }
2954
2955 pub fn field(&self, name: &str) -> Option<Value> {
2959 match name {
2960 n if n == TASK_FIELD_NAME => {
2961 Some(PrimitiveValue::String(self.data.name.clone()).into())
2962 }
2963 n if n == TASK_FIELD_ID => Some(PrimitiveValue::String(self.data.id.clone()).into()),
2964 n if n == TASK_FIELD_CONTAINER => Some(
2965 self.data
2966 .container
2967 .clone()
2968 .map(|c| PrimitiveValue::String(c).into())
2969 .unwrap_or(Value::None),
2970 ),
2971 n if n == TASK_FIELD_CPU => Some(self.data.cpu.into()),
2972 n if n == TASK_FIELD_MEMORY => Some(self.data.memory.into()),
2973 n if n == TASK_FIELD_GPU => Some(self.data.gpu.clone().into()),
2974 n if n == TASK_FIELD_FPGA => Some(self.data.fpga.clone().into()),
2975 n if n == TASK_FIELD_DISKS => Some(self.data.disks.clone().into()),
2976 n if n == TASK_FIELD_ATTEMPT => Some(self.attempt.into()),
2977 n if n == TASK_FIELD_END_TIME => {
2978 Some(self.data.end_time.map(Into::into).unwrap_or(Value::None))
2979 }
2980 n if n == TASK_FIELD_RETURN_CODE => {
2981 Some(self.return_code.map(Into::into).unwrap_or(Value::None))
2982 }
2983 n if n == TASK_FIELD_META => Some(self.data.meta.clone().into()),
2984 n if n == TASK_FIELD_PARAMETER_META => Some(self.data.parameter_meta.clone().into()),
2985 n if n == TASK_FIELD_EXT => Some(self.data.ext.clone().into()),
2986 _ => None,
2987 }
2988 }
2989}
2990
2991#[derive(Debug, Clone)]
2995pub struct HintsValue(Object);
2996
2997impl HintsValue {
2998 pub fn as_object(&self) -> &Object {
3000 &self.0
3001 }
3002}
3003
3004impl fmt::Display for HintsValue {
3005 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3006 write!(f, "hints {{")?;
3007
3008 for (i, (k, v)) in self.0.iter().enumerate() {
3009 if i > 0 {
3010 write!(f, ", ")?;
3011 }
3012
3013 write!(f, "{k}: {v}")?;
3014 }
3015
3016 write!(f, "}}")
3017 }
3018}
3019
3020impl From<Object> for HintsValue {
3021 fn from(value: Object) -> Self {
3022 Self(value)
3023 }
3024}
3025
3026#[derive(Debug, Clone)]
3030pub struct InputValue(Object);
3031
3032impl InputValue {
3033 pub fn as_object(&self) -> &Object {
3035 &self.0
3036 }
3037}
3038
3039impl fmt::Display for InputValue {
3040 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3041 write!(f, "input {{")?;
3042
3043 for (i, (k, v)) in self.0.iter().enumerate() {
3044 if i > 0 {
3045 write!(f, ", ")?;
3046 }
3047
3048 write!(f, "{k}: {v}")?;
3049 }
3050
3051 write!(f, "}}")
3052 }
3053}
3054
3055impl From<Object> for InputValue {
3056 fn from(value: Object) -> Self {
3057 Self(value)
3058 }
3059}
3060
3061#[derive(Debug, Clone)]
3065pub struct OutputValue(Object);
3066
3067impl OutputValue {
3068 pub fn as_object(&self) -> &Object {
3070 &self.0
3071 }
3072}
3073
3074impl fmt::Display for OutputValue {
3075 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3076 write!(f, "output {{")?;
3077
3078 for (i, (k, v)) in self.0.iter().enumerate() {
3079 if i > 0 {
3080 write!(f, ", ")?;
3081 }
3082
3083 write!(f, "{k}: {v}")?;
3084 }
3085
3086 write!(f, "}}")
3087 }
3088}
3089
3090impl From<Object> for OutputValue {
3091 fn from(value: Object) -> Self {
3092 Self(value)
3093 }
3094}
3095
3096#[derive(Debug, Clone)]
3100pub struct CallValue {
3101 ty: CallType,
3103 outputs: Arc<Outputs>,
3105}
3106
3107impl CallValue {
3108 pub(crate) fn new_unchecked(ty: CallType, outputs: Arc<Outputs>) -> Self {
3111 Self { ty, outputs }
3112 }
3113
3114 pub fn ty(&self) -> &CallType {
3116 &self.ty
3117 }
3118
3119 pub fn outputs(&self) -> &Outputs {
3121 self.outputs.as_ref()
3122 }
3123}
3124
3125impl fmt::Display for CallValue {
3126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3127 write!(f, "call output {{")?;
3128
3129 for (i, (k, v)) in self.outputs.iter().enumerate() {
3130 if i > 0 {
3131 write!(f, ", ")?;
3132 }
3133
3134 write!(f, "{k}: {v}")?;
3135 }
3136
3137 write!(f, "}}")
3138 }
3139}
3140
3141#[cfg(test)]
3142mod test {
3143 use approx::assert_relative_eq;
3144 use pretty_assertions::assert_eq;
3145 use wdl_analysis::types::ArrayType;
3146 use wdl_analysis::types::MapType;
3147 use wdl_analysis::types::PairType;
3148 use wdl_analysis::types::StructType;
3149
3150 use super::*;
3151
3152 #[test]
3153 fn boolean_coercion() {
3154 assert_eq!(
3156 Value::from(false)
3157 .coerce(&PrimitiveType::Boolean.into())
3158 .expect("should coerce")
3159 .unwrap_boolean(),
3160 Value::from(false).unwrap_boolean()
3161 );
3162 assert_eq!(
3164 format!(
3165 "{e:?}",
3166 e = Value::from(true)
3167 .coerce(&PrimitiveType::String.into())
3168 .unwrap_err()
3169 ),
3170 "cannot coerce type `Boolean` to type `String`"
3171 );
3172 }
3173
3174 #[test]
3175 fn boolean_display() {
3176 assert_eq!(Value::from(false).to_string(), "false");
3177 assert_eq!(Value::from(true).to_string(), "true");
3178 }
3179
3180 #[test]
3181 fn integer_coercion() {
3182 assert_eq!(
3184 Value::from(12345)
3185 .coerce(&PrimitiveType::Integer.into())
3186 .expect("should coerce")
3187 .unwrap_integer(),
3188 Value::from(12345).unwrap_integer()
3189 );
3190 assert_relative_eq!(
3192 Value::from(12345)
3193 .coerce(&PrimitiveType::Float.into())
3194 .expect("should coerce")
3195 .unwrap_float(),
3196 Value::from(12345.0).unwrap_float()
3197 );
3198 assert_eq!(
3200 format!(
3201 "{e:?}",
3202 e = Value::from(12345)
3203 .coerce(&PrimitiveType::Boolean.into())
3204 .unwrap_err()
3205 ),
3206 "cannot coerce type `Int` to type `Boolean`"
3207 );
3208 }
3209
3210 #[test]
3211 fn integer_display() {
3212 assert_eq!(Value::from(12345).to_string(), "12345");
3213 assert_eq!(Value::from(-12345).to_string(), "-12345");
3214 }
3215
3216 #[test]
3217 fn float_coercion() {
3218 assert_relative_eq!(
3220 Value::from(12345.0)
3221 .coerce(&PrimitiveType::Float.into())
3222 .expect("should coerce")
3223 .unwrap_float(),
3224 Value::from(12345.0).unwrap_float()
3225 );
3226 assert_eq!(
3228 format!(
3229 "{e:?}",
3230 e = Value::from(12345.0)
3231 .coerce(&PrimitiveType::Integer.into())
3232 .unwrap_err()
3233 ),
3234 "cannot coerce type `Float` to type `Int`"
3235 );
3236 }
3237
3238 #[test]
3239 fn float_display() {
3240 assert_eq!(Value::from(12345.12345).to_string(), "12345.123450");
3241 assert_eq!(Value::from(-12345.12345).to_string(), "-12345.123450");
3242 }
3243
3244 #[test]
3245 fn string_coercion() {
3246 let value = PrimitiveValue::new_string("foo");
3247 assert_eq!(
3249 value
3250 .coerce(&PrimitiveType::String.into())
3251 .expect("should coerce"),
3252 value
3253 );
3254 assert_eq!(
3256 value
3257 .coerce(&PrimitiveType::File.into())
3258 .expect("should coerce"),
3259 PrimitiveValue::File(value.as_string().expect("should be string").clone())
3260 );
3261 assert_eq!(
3263 value
3264 .coerce(&PrimitiveType::Directory.into())
3265 .expect("should coerce"),
3266 PrimitiveValue::Directory(value.as_string().expect("should be string").clone())
3267 );
3268 assert_eq!(
3270 format!(
3271 "{e:?}",
3272 e = value.coerce(&PrimitiveType::Boolean.into()).unwrap_err()
3273 ),
3274 "cannot coerce type `String` to type `Boolean`"
3275 );
3276 }
3277
3278 #[test]
3279 fn string_display() {
3280 let value = PrimitiveValue::new_string("hello world!");
3281 assert_eq!(value.to_string(), "\"hello world!\"");
3282 }
3283
3284 #[test]
3285 fn file_coercion() {
3286 let value = PrimitiveValue::new_file("foo");
3287
3288 assert_eq!(
3290 value
3291 .coerce(&PrimitiveType::File.into())
3292 .expect("should coerce"),
3293 value
3294 );
3295 assert_eq!(
3297 value
3298 .coerce(&PrimitiveType::String.into())
3299 .expect("should coerce"),
3300 PrimitiveValue::String(value.as_file().expect("should be file").clone())
3301 );
3302 assert_eq!(
3304 format!(
3305 "{e:?}",
3306 e = value.coerce(&PrimitiveType::Directory.into()).unwrap_err()
3307 ),
3308 "cannot coerce type `File` to type `Directory`"
3309 );
3310 }
3311
3312 #[test]
3313 fn file_display() {
3314 let value = PrimitiveValue::new_file("/foo/bar/baz.txt");
3315 assert_eq!(value.to_string(), "\"/foo/bar/baz.txt\"");
3316 }
3317
3318 #[test]
3319 fn directory_coercion() {
3320 let value = PrimitiveValue::new_directory("foo");
3321
3322 assert_eq!(
3324 value
3325 .coerce(&PrimitiveType::Directory.into())
3326 .expect("should coerce"),
3327 value
3328 );
3329 assert_eq!(
3331 value
3332 .coerce(&PrimitiveType::String.into())
3333 .expect("should coerce"),
3334 PrimitiveValue::String(value.as_directory().expect("should be directory").clone())
3335 );
3336 assert_eq!(
3338 format!(
3339 "{e:?}",
3340 e = value.coerce(&PrimitiveType::File.into()).unwrap_err()
3341 ),
3342 "cannot coerce type `Directory` to type `File`"
3343 );
3344 }
3345
3346 #[test]
3347 fn directory_display() {
3348 let value = PrimitiveValue::new_directory("/foo/bar/baz");
3349 assert_eq!(value.to_string(), "\"/foo/bar/baz\"");
3350 }
3351
3352 #[test]
3353 fn none_coercion() {
3354 assert!(
3356 Value::None
3357 .coerce(&Type::from(PrimitiveType::String).optional())
3358 .expect("should coerce")
3359 .is_none(),
3360 );
3361
3362 assert_eq!(
3364 format!(
3365 "{e:?}",
3366 e = Value::None
3367 .coerce(&PrimitiveType::String.into())
3368 .unwrap_err()
3369 ),
3370 "cannot coerce `None` to non-optional type `String`"
3371 );
3372 }
3373
3374 #[test]
3375 fn none_display() {
3376 assert_eq!(Value::None.to_string(), "None");
3377 }
3378
3379 #[test]
3380 fn array_coercion() {
3381 let src_ty: Type = ArrayType::new(PrimitiveType::Integer).into();
3382 let target_ty: Type = ArrayType::new(PrimitiveType::Float).into();
3383
3384 let src: CompoundValue = Array::new(src_ty, [1, 2, 3])
3386 .expect("should create array value")
3387 .into();
3388 let target = src.coerce(&target_ty).expect("should coerce");
3389 assert_eq!(
3390 target.unwrap_array().to_string(),
3391 "[1.000000, 2.000000, 3.000000]"
3392 );
3393
3394 let target_ty: Type = ArrayType::new(PrimitiveType::String).into();
3396 assert_eq!(
3397 format!("{e:?}", e = src.coerce(&target_ty).unwrap_err()),
3398 r#"failed to coerce array element at index 0
3399
3400Caused by:
3401 cannot coerce type `Int` to type `String`"#
3402 );
3403 }
3404
3405 #[test]
3406 fn non_empty_array_coercion() {
3407 let ty: Type = ArrayType::new(PrimitiveType::String).into();
3408 let target_ty: Type = ArrayType::non_empty(PrimitiveType::String).into();
3409
3410 let string = PrimitiveValue::new_string("foo");
3412 let value: Value = Array::new(ty.clone(), [string])
3413 .expect("should create array")
3414 .into();
3415 assert!(value.coerce(&target_ty).is_ok(), "should coerce");
3416
3417 let value: Value = Array::new::<Value>(ty, [])
3419 .expect("should create array")
3420 .into();
3421 assert_eq!(
3422 format!("{e:?}", e = value.coerce(&target_ty).unwrap_err()),
3423 "cannot coerce empty array value to non-empty array type `Array[String]+`"
3424 );
3425 }
3426
3427 #[test]
3428 fn array_display() {
3429 let ty: Type = ArrayType::new(PrimitiveType::Integer).into();
3430 let value: Value = Array::new(ty, [1, 2, 3])
3431 .expect("should create array")
3432 .into();
3433
3434 assert_eq!(value.to_string(), "[1, 2, 3]");
3435 }
3436
3437 #[test]
3438 fn map_coerce() {
3439 let key1 = PrimitiveValue::new_file("foo");
3440 let value1 = PrimitiveValue::new_string("bar");
3441 let key2 = PrimitiveValue::new_file("baz");
3442 let value2 = PrimitiveValue::new_string("qux");
3443
3444 let ty = MapType::new(PrimitiveType::File, PrimitiveType::String);
3445 let value: Value = Map::new(ty, [(key1, value1), (key2, value2)])
3446 .expect("should create map value")
3447 .into();
3448
3449 let ty = MapType::new(PrimitiveType::String, PrimitiveType::File).into();
3451 let value = value.coerce(&ty).expect("value should coerce");
3452 assert_eq!(value.to_string(), r#"{"foo": "bar", "baz": "qux"}"#);
3453
3454 let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::File).into();
3456 assert_eq!(
3457 format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3458 r#"failed to coerce map key for element at index 0
3459
3460Caused by:
3461 cannot coerce type `String` to type `Int`"#
3462 );
3463
3464 let ty = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
3466 assert_eq!(
3467 format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3468 r#"failed to coerce map value for element at index 0
3469
3470Caused by:
3471 cannot coerce type `File` to type `Int`"#
3472 );
3473
3474 let ty = StructType::new(
3476 "Foo",
3477 [("foo", PrimitiveType::File), ("baz", PrimitiveType::File)],
3478 )
3479 .into();
3480 let struct_value = value.coerce(&ty).expect("value should coerce");
3481 assert_eq!(struct_value.to_string(), r#"Foo {foo: "bar", baz: "qux"}"#);
3482
3483 let ty = StructType::new(
3485 "Foo",
3486 [
3487 ("foo", PrimitiveType::File),
3488 ("baz", PrimitiveType::File),
3489 ("qux", PrimitiveType::File),
3490 ],
3491 )
3492 .into();
3493 assert_eq!(
3494 format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3495 "cannot coerce a map of 2 elements to struct type `Foo` as the struct has 3 members"
3496 );
3497
3498 let object_value = value.coerce(&Type::Object).expect("value should coerce");
3500 assert_eq!(
3501 object_value.to_string(),
3502 r#"object {foo: "bar", baz: "qux"}"#
3503 );
3504 }
3505
3506 #[test]
3507 fn map_display() {
3508 let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::Boolean);
3509 let value: Value = Map::new(ty, [(1, true), (2, false)])
3510 .expect("should create map value")
3511 .into();
3512 assert_eq!(value.to_string(), "{1: true, 2: false}");
3513 }
3514
3515 #[test]
3516 fn pair_coercion() {
3517 let left = PrimitiveValue::new_file("foo");
3518 let right = PrimitiveValue::new_string("bar");
3519
3520 let ty = PairType::new(PrimitiveType::File, PrimitiveType::String);
3521 let value: Value = Pair::new(ty, left, right)
3522 .expect("should create map value")
3523 .into();
3524
3525 let ty = PairType::new(PrimitiveType::String, PrimitiveType::File).into();
3527 let value = value.coerce(&ty).expect("value should coerce");
3528 assert_eq!(value.to_string(), r#"("foo", "bar")"#);
3529
3530 let ty = PairType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
3532 assert_eq!(
3533 format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3534 r#"failed to coerce pair's left value
3535
3536Caused by:
3537 cannot coerce type `String` to type `Int`"#
3538 );
3539 }
3540
3541 #[test]
3542 fn pair_display() {
3543 let ty = PairType::new(PrimitiveType::Integer, PrimitiveType::Boolean);
3544 let value: Value = Pair::new(ty, 12345, false)
3545 .expect("should create pair value")
3546 .into();
3547 assert_eq!(value.to_string(), "(12345, false)");
3548 }
3549
3550 #[test]
3551 fn struct_coercion() {
3552 let ty = StructType::new(
3553 "Foo",
3554 [
3555 ("foo", PrimitiveType::Float),
3556 ("bar", PrimitiveType::Float),
3557 ("baz", PrimitiveType::Float),
3558 ],
3559 );
3560 let value: Value = Struct::new(ty, [("foo", 1.0), ("bar", 2.0), ("baz", 3.0)])
3561 .expect("should create map value")
3562 .into();
3563
3564 let ty = MapType::new(PrimitiveType::String, PrimitiveType::Float).into();
3566 let map_value = value.coerce(&ty).expect("value should coerce");
3567 assert_eq!(
3568 map_value.to_string(),
3569 r#"{"foo": 1.000000, "bar": 2.000000, "baz": 3.000000}"#
3570 );
3571
3572 let ty = StructType::new(
3574 "Bar",
3575 [
3576 ("foo", PrimitiveType::Float),
3577 ("bar", PrimitiveType::Float),
3578 ("baz", PrimitiveType::Float),
3579 ],
3580 )
3581 .into();
3582 let struct_value = value.coerce(&ty).expect("value should coerce");
3583 assert_eq!(
3584 struct_value.to_string(),
3585 r#"Bar {foo: 1.000000, bar: 2.000000, baz: 3.000000}"#
3586 );
3587
3588 let object_value = value.coerce(&Type::Object).expect("value should coerce");
3590 assert_eq!(
3591 object_value.to_string(),
3592 r#"object {foo: 1.000000, bar: 2.000000, baz: 3.000000}"#
3593 );
3594 }
3595
3596 #[test]
3597 fn struct_display() {
3598 let ty = StructType::new(
3599 "Foo",
3600 [
3601 ("foo", PrimitiveType::Float),
3602 ("bar", PrimitiveType::String),
3603 ("baz", PrimitiveType::Integer),
3604 ],
3605 );
3606 let value: Value = Struct::new(
3607 ty,
3608 [
3609 ("foo", Value::from(1.101)),
3610 ("bar", PrimitiveValue::new_string("foo").into()),
3611 ("baz", 1234.into()),
3612 ],
3613 )
3614 .expect("should create map value")
3615 .into();
3616 assert_eq!(
3617 value.to_string(),
3618 r#"Foo {foo: 1.101000, bar: "foo", baz: 1234}"#
3619 );
3620 }
3621}