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(Object::new(members))))
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(crate) fn new(members: IndexMap<String, Value>) -> Self {
1797 Self {
1798 members: if members.is_empty() {
1799 None
1800 } else {
1801 Some(Arc::new(members))
1802 },
1803 }
1804 }
1805
1806 pub fn empty() -> Self {
1808 Self::new(IndexMap::default())
1809 }
1810
1811 pub fn from_v1_metadata<N: TreeNode>(
1813 items: impl Iterator<Item = v1::MetadataObjectItem<N>>,
1814 ) -> Self {
1815 Object::new(
1816 items
1817 .map(|i| {
1818 (
1819 i.name().text().to_string(),
1820 Value::from_v1_metadata(&i.value()),
1821 )
1822 })
1823 .collect::<IndexMap<_, _>>(),
1824 )
1825 }
1826
1827 pub fn ty(&self) -> Type {
1829 Type::Object
1830 }
1831
1832 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
1834 self.members
1835 .as_ref()
1836 .map(|m| Either::Left(m.iter().map(|(k, v)| (k.as_str(), v))))
1837 .unwrap_or(Either::Right(std::iter::empty()))
1838 }
1839
1840 pub fn keys(&self) -> impl Iterator<Item = &str> {
1842 self.members
1843 .as_ref()
1844 .map(|m| Either::Left(m.keys().map(|k| k.as_str())))
1845 .unwrap_or(Either::Right(std::iter::empty()))
1846 }
1847
1848 pub fn values(&self) -> impl Iterator<Item = &Value> {
1850 self.members
1851 .as_ref()
1852 .map(|m| Either::Left(m.values()))
1853 .unwrap_or(Either::Right(std::iter::empty()))
1854 }
1855
1856 pub fn contains_key(&self, key: &str) -> bool {
1858 self.members
1859 .as_ref()
1860 .map(|m| m.contains_key(key))
1861 .unwrap_or(false)
1862 }
1863
1864 pub fn get(&self, key: &str) -> Option<&Value> {
1866 self.members.as_ref().and_then(|m| m.get(key))
1867 }
1868
1869 pub fn len(&self) -> usize {
1871 self.members.as_ref().map(|m| m.len()).unwrap_or(0)
1872 }
1873
1874 pub fn is_empty(&self) -> bool {
1876 self.len() == 0
1877 }
1878}
1879
1880impl fmt::Display for Object {
1881 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1882 write!(f, "object {{")?;
1883
1884 for (i, (k, v)) in self.iter().enumerate() {
1885 if i > 0 {
1886 write!(f, ", ")?;
1887 }
1888
1889 write!(f, "{k}: {v}")?;
1890 }
1891
1892 write!(f, "}}")
1893 }
1894}
1895
1896#[derive(Debug, Clone)]
1900pub struct Struct {
1901 ty: Type,
1903 name: Arc<String>,
1905 pub(crate) members: Arc<IndexMap<String, Value>>,
1907}
1908
1909impl Struct {
1910 pub fn new<S, V>(ty: impl Into<Type>, members: impl IntoIterator<Item = (S, V)>) -> Result<Self>
1919 where
1920 S: Into<String>,
1921 V: Into<Value>,
1922 {
1923 let ty = ty.into();
1924 if let Type::Compound(CompoundType::Struct(ty), optional) = ty {
1925 let mut members = members
1926 .into_iter()
1927 .map(|(n, v)| {
1928 let n = n.into();
1929 let v = v.into();
1930 let v = v
1931 .coerce(ty.members().get(&n).ok_or_else(|| {
1932 anyhow!("struct does not contain a member named `{n}`")
1933 })?)
1934 .with_context(|| format!("failed to coerce struct member `{n}`"))?;
1935 Ok((n, v))
1936 })
1937 .collect::<Result<IndexMap<_, _>>>()?;
1938
1939 for (name, ty) in ty.members().iter() {
1940 if ty.is_optional() {
1942 if !members.contains_key(name) {
1943 members.insert(name.clone(), Value::None);
1944 }
1945 } else {
1946 if !members.contains_key(name) {
1948 bail!("missing a value for struct member `{name}`");
1949 }
1950 }
1951 }
1952
1953 let name = ty.name().to_string();
1954 return Ok(Self {
1955 ty: Type::Compound(CompoundType::Struct(ty), optional),
1956 name: Arc::new(name),
1957 members: Arc::new(members),
1958 });
1959 }
1960
1961 panic!("type `{ty}` is not a struct type");
1962 }
1963
1964 pub(crate) fn new_unchecked(
1967 ty: Type,
1968 name: Arc<String>,
1969 members: Arc<IndexMap<String, Value>>,
1970 ) -> Self {
1971 assert!(ty.as_struct().is_some());
1972 Self { ty, name, members }
1973 }
1974
1975 pub fn ty(&self) -> Type {
1977 self.ty.clone()
1978 }
1979
1980 pub fn name(&self) -> &Arc<String> {
1982 &self.name
1983 }
1984
1985 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
1987 self.members.iter().map(|(k, v)| (k.as_str(), v))
1988 }
1989
1990 pub fn keys(&self) -> impl Iterator<Item = &str> {
1992 self.members.keys().map(|k| k.as_str())
1993 }
1994
1995 pub fn values(&self) -> impl Iterator<Item = &Value> {
1997 self.members.values()
1998 }
1999
2000 pub fn contains_key(&self, key: &str) -> bool {
2002 self.members.contains_key(key)
2003 }
2004
2005 pub fn get(&self, key: &str) -> Option<&Value> {
2007 self.members.get(key)
2008 }
2009}
2010
2011impl fmt::Display for Struct {
2012 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2013 write!(f, "{name} {{", name = self.name)?;
2014
2015 for (i, (k, v)) in self.members.iter().enumerate() {
2016 if i > 0 {
2017 write!(f, ", ")?;
2018 }
2019
2020 write!(f, "{k}: {v}")?;
2021 }
2022
2023 write!(f, "}}")
2024 }
2025}
2026
2027#[derive(Debug, Clone)]
2031pub enum CompoundValue {
2032 Pair(Pair),
2034 Array(Array),
2036 Map(Map),
2038 Object(Object),
2040 Struct(Struct),
2042}
2043
2044impl CompoundValue {
2045 pub fn ty(&self) -> Type {
2047 match self {
2048 CompoundValue::Pair(v) => v.ty(),
2049 CompoundValue::Array(v) => v.ty(),
2050 CompoundValue::Map(v) => v.ty(),
2051 CompoundValue::Object(v) => v.ty(),
2052 CompoundValue::Struct(v) => v.ty(),
2053 }
2054 }
2055
2056 pub fn as_pair(&self) -> Option<&Pair> {
2060 match self {
2061 Self::Pair(v) => Some(v),
2062 _ => None,
2063 }
2064 }
2065
2066 pub fn unwrap_pair(self) -> Pair {
2072 match self {
2073 Self::Pair(v) => v,
2074 _ => panic!("value is not a pair"),
2075 }
2076 }
2077
2078 pub fn as_array(&self) -> Option<&Array> {
2082 match self {
2083 Self::Array(v) => Some(v),
2084 _ => None,
2085 }
2086 }
2087
2088 pub fn unwrap_array(self) -> Array {
2094 match self {
2095 Self::Array(v) => v,
2096 _ => panic!("value is not an array"),
2097 }
2098 }
2099
2100 pub fn as_map(&self) -> Option<&Map> {
2104 match self {
2105 Self::Map(v) => Some(v),
2106 _ => None,
2107 }
2108 }
2109
2110 pub fn unwrap_map(self) -> Map {
2116 match self {
2117 Self::Map(v) => v,
2118 _ => panic!("value is not a map"),
2119 }
2120 }
2121
2122 pub fn as_object(&self) -> Option<&Object> {
2126 match self {
2127 Self::Object(v) => Some(v),
2128 _ => None,
2129 }
2130 }
2131
2132 pub fn unwrap_object(self) -> Object {
2138 match self {
2139 Self::Object(v) => v,
2140 _ => panic!("value is not an object"),
2141 }
2142 }
2143
2144 pub fn as_struct(&self) -> Option<&Struct> {
2148 match self {
2149 Self::Struct(v) => Some(v),
2150 _ => None,
2151 }
2152 }
2153
2154 pub fn unwrap_struct(self) -> Struct {
2160 match self {
2161 Self::Struct(v) => v,
2162 _ => panic!("value is not a struct"),
2163 }
2164 }
2165
2166 pub fn equals(left: &Self, right: &Self) -> Option<bool> {
2172 if left.ty() != right.ty() {
2175 return None;
2176 }
2177
2178 match (left, right) {
2179 (Self::Pair(left), Self::Pair(right)) => Some(
2180 Value::equals(left.left(), right.left())?
2181 && Value::equals(left.right(), right.right())?,
2182 ),
2183 (CompoundValue::Array(left), CompoundValue::Array(right)) => Some(
2184 left.len() == right.len()
2185 && left
2186 .as_slice()
2187 .iter()
2188 .zip(right.as_slice())
2189 .all(|(l, r)| Value::equals(l, r).unwrap_or(false)),
2190 ),
2191 (CompoundValue::Map(left), CompoundValue::Map(right)) => Some(
2192 left.len() == right.len()
2193 && left.iter().zip(right.iter()).all(|((lk, lv), (rk, rv))| {
2195 match (lk, rk) {
2196 (None, None) => {},
2197 (Some(lk), Some(rk)) if lk == rk => {},
2198 _ => return false
2199 }
2200
2201 Value::equals(lv, rv).unwrap_or(false)
2202 }),
2203 ),
2204 (CompoundValue::Object(left), CompoundValue::Object(right)) => Some(
2205 left.len() == right.len()
2206 && left.iter().all(|(k, left)| match right.get(k) {
2207 Some(right) => Value::equals(left, right).unwrap_or(false),
2208 None => false,
2209 }),
2210 ),
2211 (
2212 CompoundValue::Struct(Struct { members: left, .. }),
2213 CompoundValue::Struct(Struct { members: right, .. }),
2214 ) => Some(
2215 left.len() == right.len()
2216 && left.iter().all(|(k, left)| match right.get(k) {
2217 Some(right) => Value::equals(left, right).unwrap_or(false),
2218 None => false,
2219 }),
2220 ),
2221 _ => None,
2222 }
2223 }
2224
2225 fn visit_paths(&self, cb: &mut impl FnMut(bool, &PrimitiveValue) -> Result<()>) -> Result<()> {
2229 match self {
2230 Self::Pair(pair) => {
2231 let ty = pair.ty.as_pair().expect("should be a pair type");
2232 pair.left().visit_paths(ty.left_type().is_optional(), cb)?;
2233 pair.right()
2234 .visit_paths(ty.right_type().is_optional(), cb)?;
2235 }
2236 Self::Array(array) => {
2237 let ty = array.ty.as_array().expect("should be an array type");
2238 let optional = ty.element_type().is_optional();
2239 if let Some(elements) = &array.elements {
2240 for v in elements.iter() {
2241 v.visit_paths(optional, cb)?;
2242 }
2243 }
2244 }
2245 Self::Map(map) => {
2246 let ty = map.ty.as_map().expect("should be a map type");
2247 let (key_optional, value_optional) =
2248 (ty.key_type().is_optional(), ty.value_type().is_optional());
2249 if let Some(elements) = &map.elements {
2250 for (k, v) in elements.iter() {
2251 if let Some(k) = k {
2252 k.visit_paths(key_optional, cb)?;
2253 }
2254
2255 v.visit_paths(value_optional, cb)?;
2256 }
2257 }
2258 }
2259 Self::Object(object) => {
2260 if let Some(members) = &object.members {
2261 for v in members.values() {
2262 v.visit_paths(false, cb)?;
2263 }
2264 }
2265 }
2266 Self::Struct(s) => {
2267 let ty = s.ty.as_struct().expect("should be a struct type");
2268 for (n, v) in s.members.iter() {
2269 v.visit_paths(ty.members()[n].is_optional(), cb)?;
2270 }
2271 }
2272 }
2273
2274 Ok(())
2275 }
2276
2277 fn visit_paths_mut(
2284 &mut self,
2285 cb: &mut impl FnMut(bool, &mut PrimitiveValue) -> Result<bool>,
2286 ) -> Result<()> {
2287 match self {
2288 Self::Pair(pair) => {
2289 let ty = pair.ty.as_pair().expect("should be a pair type");
2290 let (left_optional, right_optional) =
2291 (ty.left_type().is_optional(), ty.right_type().is_optional());
2292 let values = Arc::make_mut(&mut pair.values);
2293 values.0.visit_paths_mut(left_optional, cb)?;
2294 values.1.visit_paths_mut(right_optional, cb)?;
2295 }
2296 Self::Array(array) => {
2297 let ty = array.ty.as_array().expect("should be an array type");
2298 let optional = ty.element_type().is_optional();
2299 if let Some(elements) = &mut array.elements {
2300 for v in Arc::make_mut(elements) {
2301 v.visit_paths_mut(optional, cb)?;
2302 }
2303 }
2304 }
2305 Self::Map(map) => {
2306 let ty = map.ty.as_map().expect("should be a map type");
2307 let (key_optional, value_optional) =
2308 (ty.key_type().is_optional(), ty.value_type().is_optional());
2309 if let Some(elements) = &mut map.elements {
2310 if elements
2311 .iter()
2312 .find_map(|(k, _)| {
2313 k.as_ref().map(|v| {
2314 matches!(v, PrimitiveValue::File(_) | PrimitiveValue::Directory(_))
2315 })
2316 })
2317 .unwrap_or(false)
2318 {
2319 let elements = Arc::make_mut(elements);
2322 let new = elements
2323 .drain(..)
2324 .map(|(mut k, mut v)| {
2325 if let Some(v) = &mut k {
2326 if !v.visit_paths_mut(key_optional, cb)? {
2327 k = None;
2328 }
2329 }
2330
2331 v.visit_paths_mut(value_optional, cb)?;
2332 Ok((k, v))
2333 })
2334 .collect::<Result<Vec<_>>>()?;
2335 elements.extend(new);
2336 } else {
2337 for v in Arc::make_mut(elements).values_mut() {
2339 v.visit_paths_mut(value_optional, cb)?;
2340 }
2341 }
2342 }
2343 }
2344 Self::Object(object) => {
2345 if let Some(members) = &mut object.members {
2346 for v in Arc::make_mut(members).values_mut() {
2347 v.visit_paths_mut(false, cb)?;
2348 }
2349 }
2350 }
2351 Self::Struct(s) => {
2352 let ty = s.ty.as_struct().expect("should be a struct type");
2353 for (n, v) in Arc::make_mut(&mut s.members).iter_mut() {
2354 v.visit_paths_mut(ty.members()[n].is_optional(), cb)?;
2355 }
2356 }
2357 }
2358
2359 Ok(())
2360 }
2361
2362 fn clone_as_required(&self) -> Self {
2364 match self {
2365 Self::Pair(v) => Self::Pair(Pair {
2366 ty: v.ty.require(),
2367 values: v.values.clone(),
2368 }),
2369 Self::Array(v) => Self::Array(Array {
2370 ty: v.ty.require(),
2371 elements: v.elements.clone(),
2372 }),
2373 Self::Map(v) => Self::Map(Map {
2374 ty: v.ty.require(),
2375 elements: v.elements.clone(),
2376 }),
2377 Self::Object(_) => self.clone(),
2378 Self::Struct(v) => Self::Struct(Struct {
2379 ty: v.ty.require(),
2380 name: v.name.clone(),
2381 members: v.members.clone(),
2382 }),
2383 }
2384 }
2385
2386 fn clone_as_optional(&self) -> Self {
2388 match self {
2389 Self::Pair(v) => Self::Pair(Pair {
2390 ty: v.ty.optional(),
2391 values: v.values.clone(),
2392 }),
2393 Self::Array(v) => Self::Array(Array {
2394 ty: v.ty.optional(),
2395 elements: v.elements.clone(),
2396 }),
2397 Self::Map(v) => Self::Map(Map {
2398 ty: v.ty.optional(),
2399 elements: v.elements.clone(),
2400 }),
2401 Self::Object(_) => self.clone(),
2402 Self::Struct(v) => Self::Struct(Struct {
2403 ty: v.ty.optional(),
2404 name: v.name.clone(),
2405 members: v.members.clone(),
2406 }),
2407 }
2408 }
2409}
2410
2411impl fmt::Display for CompoundValue {
2412 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2413 match self {
2414 Self::Pair(v) => v.fmt(f),
2415 Self::Array(v) => v.fmt(f),
2416 Self::Map(v) => v.fmt(f),
2417 Self::Object(v) => v.fmt(f),
2418 Self::Struct(v) => v.fmt(f),
2419 }
2420 }
2421}
2422
2423impl Coercible for CompoundValue {
2424 fn coerce(&self, target: &Type) -> Result<Self> {
2425 if target.is_union() || target.is_none() || self.ty().eq(target) {
2426 return Ok(self.clone());
2427 }
2428
2429 if let Type::Compound(target_ty, _) = target {
2430 match (self, target_ty) {
2431 (Self::Array(v), CompoundType::Array(target_ty)) => {
2433 if v.is_empty() && target_ty.is_non_empty() {
2436 bail!("cannot coerce empty array value to non-empty array type `{target}`",);
2437 }
2438
2439 return Ok(Self::Array(Array::new(
2440 target.clone(),
2441 v.as_slice().iter().cloned(),
2442 )?));
2443 }
2444 (Self::Map(v), CompoundType::Map(_)) => {
2446 return Ok(Self::Map(Map::new(
2447 target.clone(),
2448 v.iter().map(|(k, v)| {
2449 (k.clone().map(Into::into).unwrap_or(Value::None), v.clone())
2450 }),
2451 )?));
2452 }
2453 (Self::Pair(v), CompoundType::Pair(_)) => {
2455 return Ok(Self::Pair(Pair::new(
2456 target.clone(),
2457 v.values.0.clone(),
2458 v.values.1.clone(),
2459 )?));
2460 }
2461 (Self::Map(v), CompoundType::Struct(target_ty)) => {
2463 let len = v.len();
2464 let expected_len = target_ty.members().len();
2465
2466 if len != expected_len {
2467 bail!(
2468 "cannot coerce a map of {len} element{s1} to struct type `{target}` \
2469 as the struct has {expected_len} member{s2}",
2470 s1 = if len == 1 { "" } else { "s" },
2471 s2 = if expected_len == 1 { "" } else { "s" }
2472 );
2473 }
2474
2475 return Ok(Self::Struct(Struct {
2476 ty: target.clone(),
2477 name: target_ty.name().clone(),
2478 members: Arc::new(
2479 v.iter()
2480 .map(|(k, v)| {
2481 let k: String = k
2482 .as_ref()
2483 .and_then(|k| k.as_string())
2484 .with_context(|| {
2485 format!(
2486 "cannot coerce a map with a non-string key type \
2487 to struct type `{target}`"
2488 )
2489 })?
2490 .to_string();
2491 let ty = target_ty.members().get(&k).with_context(|| {
2492 format!(
2493 "cannot coerce a map with key `{k}` to struct type \
2494 `{target}` as the struct does not contain a member \
2495 with that name"
2496 )
2497 })?;
2498 let v = v.coerce(ty).with_context(|| {
2499 format!("failed to coerce value of map key `{k}")
2500 })?;
2501 Ok((k, v))
2502 })
2503 .collect::<Result<_>>()?,
2504 ),
2505 }));
2506 }
2507 (Self::Struct(Struct { members, .. }), CompoundType::Map(map_ty)) => {
2510 if map_ty.key_type().as_primitive() != Some(PrimitiveType::String) {
2511 bail!(
2512 "cannot coerce a struct or object to type `{target}` as it requires a \
2513 `String` key type"
2514 );
2515 }
2516
2517 let value_ty = map_ty.value_type();
2518 return Ok(Self::Map(Map::new_unchecked(
2519 target.clone(),
2520 members
2521 .iter()
2522 .map(|(n, v)| {
2523 let v = v
2524 .coerce(value_ty)
2525 .with_context(|| format!("failed to coerce member `{n}`"))?;
2526 Ok((PrimitiveValue::new_string(n).into(), v))
2527 })
2528 .collect::<Result<_>>()?,
2529 )));
2530 }
2531 (Self::Object(object), CompoundType::Map(map_ty)) => {
2532 if map_ty.key_type().as_primitive() != Some(PrimitiveType::String) {
2533 bail!(
2534 "cannot coerce a struct or object to type `{target}` as it requires a \
2535 `String` key type",
2536 );
2537 }
2538
2539 let value_ty = map_ty.value_type();
2540 return Ok(Self::Map(Map::new_unchecked(
2541 target.clone(),
2542 object
2543 .iter()
2544 .map(|(n, v)| {
2545 let v = v
2546 .coerce(value_ty)
2547 .with_context(|| format!("failed to coerce member `{n}`"))?;
2548 Ok((PrimitiveValue::new_string(n).into(), v))
2549 })
2550 .collect::<Result<_>>()?,
2551 )));
2552 }
2553 (Self::Object(v), CompoundType::Struct(_)) => {
2555 return Ok(Self::Struct(Struct::new(
2556 target.clone(),
2557 v.iter().map(|(k, v)| (k, v.clone())),
2558 )?));
2559 }
2560 (Self::Struct(v), CompoundType::Struct(struct_ty)) => {
2562 let len = v.members.len();
2563 let expected_len = struct_ty.members().len();
2564
2565 if len != expected_len {
2566 bail!(
2567 "cannot coerce a struct of {len} members{s1} to struct type \
2568 `{target}` as the target struct has {expected_len} member{s2}",
2569 s1 = if len == 1 { "" } else { "s" },
2570 s2 = if expected_len == 1 { "" } else { "s" }
2571 );
2572 }
2573
2574 return Ok(Self::Struct(Struct {
2575 ty: target.clone(),
2576 name: struct_ty.name().clone(),
2577 members: Arc::new(
2578 v.members
2579 .iter()
2580 .map(|(k, v)| {
2581 let ty = struct_ty.members().get(k).ok_or_else(|| {
2582 anyhow!(
2583 "cannot coerce a struct with member `{k}` to struct \
2584 type `{target}` as the target struct does not \
2585 contain a member with that name",
2586 )
2587 })?;
2588 let v = v.coerce(ty).with_context(|| {
2589 format!("failed to coerce member `{k}`")
2590 })?;
2591 Ok((k.clone(), v))
2592 })
2593 .collect::<Result<_>>()?,
2594 ),
2595 }));
2596 }
2597 _ => {}
2598 }
2599 }
2600
2601 if let Type::Object = target {
2602 match self {
2603 Self::Map(v) => {
2605 return Ok(Self::Object(Object::new(
2606 v.iter()
2607 .map(|(k, v)| {
2608 let k = k
2609 .as_ref()
2610 .and_then(|k| k.as_string())
2611 .context(
2612 "cannot coerce a map with a non-string key type to type \
2613 `Object`",
2614 )?
2615 .to_string();
2616 Ok((k, v.clone()))
2617 })
2618 .collect::<Result<IndexMap<_, _>>>()?,
2619 )));
2620 }
2621 Self::Struct(v) => {
2623 return Ok(Self::Object(Object {
2624 members: Some(v.members.clone()),
2625 }));
2626 }
2627 _ => {}
2628 };
2629 }
2630
2631 bail!(
2632 "cannot coerce a value of type `{ty}` to type `{target}`",
2633 ty = self.ty()
2634 );
2635 }
2636}
2637
2638impl From<Pair> for CompoundValue {
2639 fn from(value: Pair) -> Self {
2640 Self::Pair(value)
2641 }
2642}
2643
2644impl From<Array> for CompoundValue {
2645 fn from(value: Array) -> Self {
2646 Self::Array(value)
2647 }
2648}
2649
2650impl From<Map> for CompoundValue {
2651 fn from(value: Map) -> Self {
2652 Self::Map(value)
2653 }
2654}
2655
2656impl From<Object> for CompoundValue {
2657 fn from(value: Object) -> Self {
2658 Self::Object(value)
2659 }
2660}
2661
2662impl From<Struct> for CompoundValue {
2663 fn from(value: Struct) -> Self {
2664 Self::Struct(value)
2665 }
2666}
2667
2668impl serde::Serialize for CompoundValue {
2669 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2670 where
2671 S: serde::Serializer,
2672 {
2673 use serde::ser::Error;
2674
2675 match self {
2676 Self::Pair(_) => Err(S::Error::custom("a pair cannot be serialized")),
2677 Self::Array(v) => {
2678 let mut s = serializer.serialize_seq(Some(v.len()))?;
2679 for v in v.as_slice() {
2680 s.serialize_element(v)?;
2681 }
2682
2683 s.end()
2684 }
2685 Self::Map(v) => {
2686 if !v
2687 .ty()
2688 .as_map()
2689 .expect("type should be a map")
2690 .key_type()
2691 .is_coercible_to(&PrimitiveType::String.into())
2692 {
2693 return Err(S::Error::custom(
2694 "only maps with `String` key types may be serialized",
2695 ));
2696 }
2697
2698 let mut s = serializer.serialize_map(Some(v.len()))?;
2699 for (k, v) in v.iter() {
2700 s.serialize_entry(k, v)?;
2701 }
2702
2703 s.end()
2704 }
2705 Self::Object(object) => {
2706 let mut s = serializer.serialize_map(Some(object.len()))?;
2707 for (k, v) in object.iter() {
2708 s.serialize_entry(k, v)?;
2709 }
2710
2711 s.end()
2712 }
2713 Self::Struct(Struct { members, .. }) => {
2714 let mut s = serializer.serialize_map(Some(members.len()))?;
2715 for (k, v) in members.iter() {
2716 s.serialize_entry(k, v)?;
2717 }
2718
2719 s.end()
2720 }
2721 }
2722 }
2723}
2724
2725#[derive(Debug)]
2727struct TaskData {
2728 name: Arc<String>,
2730 id: Arc<String>,
2732 container: Option<Arc<String>>,
2734 cpu: f64,
2736 memory: i64,
2738 gpu: Array,
2743 fpga: Array,
2748 disks: Map,
2755 end_time: Option<i64>,
2759 meta: Object,
2761 parameter_meta: Object,
2763 ext: Object,
2765}
2766
2767#[derive(Debug, Clone)]
2771pub struct TaskValue {
2772 data: Arc<TaskData>,
2774 attempt: i64,
2779 return_code: Option<i64>,
2783}
2784
2785impl TaskValue {
2786 pub(crate) fn new_v1<N: TreeNode>(
2788 name: impl Into<String>,
2789 id: impl Into<String>,
2790 definition: &v1::TaskDefinition<N>,
2791 constraints: TaskExecutionConstraints,
2792 attempt: i64,
2793 ) -> Self {
2794 Self {
2795 data: Arc::new(TaskData {
2796 name: Arc::new(name.into()),
2797 id: Arc::new(id.into()),
2798 container: constraints.container.map(Into::into),
2799 cpu: constraints.cpu,
2800 memory: constraints.memory,
2801 gpu: Array::new_unchecked(
2802 ANALYSIS_STDLIB.array_string_type().clone(),
2803 constraints
2804 .gpu
2805 .into_iter()
2806 .map(|v| PrimitiveValue::new_string(v).into())
2807 .collect(),
2808 ),
2809 fpga: Array::new_unchecked(
2810 ANALYSIS_STDLIB.array_string_type().clone(),
2811 constraints
2812 .fpga
2813 .into_iter()
2814 .map(|v| PrimitiveValue::new_string(v).into())
2815 .collect(),
2816 ),
2817 disks: Map::new_unchecked(
2818 ANALYSIS_STDLIB.map_string_int_type().clone(),
2819 constraints
2820 .disks
2821 .into_iter()
2822 .map(|(k, v)| (Some(PrimitiveValue::new_string(k)), v.into()))
2823 .collect(),
2824 ),
2825 end_time: None,
2826 meta: definition
2827 .metadata()
2828 .map(|s| Object::from_v1_metadata(s.items()))
2829 .unwrap_or_else(Object::empty),
2830 parameter_meta: definition
2831 .parameter_metadata()
2832 .map(|s| Object::from_v1_metadata(s.items()))
2833 .unwrap_or_else(Object::empty),
2834 ext: Object::empty(),
2835 }),
2836 attempt,
2837 return_code: None,
2838 }
2839 }
2840
2841 pub fn name(&self) -> &Arc<String> {
2843 &self.data.name
2844 }
2845
2846 pub fn id(&self) -> &Arc<String> {
2848 &self.data.id
2849 }
2850
2851 pub fn container(&self) -> Option<&Arc<String>> {
2853 self.data.container.as_ref()
2854 }
2855
2856 pub fn cpu(&self) -> f64 {
2858 self.data.cpu
2859 }
2860
2861 pub fn memory(&self) -> i64 {
2863 self.data.memory
2864 }
2865
2866 pub fn gpu(&self) -> &Array {
2871 &self.data.gpu
2872 }
2873
2874 pub fn fpga(&self) -> &Array {
2879 &self.data.fpga
2880 }
2881
2882 pub fn disks(&self) -> &Map {
2889 &self.data.disks
2890 }
2891
2892 pub fn attempt(&self) -> i64 {
2897 self.attempt
2898 }
2899
2900 pub fn end_time(&self) -> Option<i64> {
2904 self.data.end_time
2905 }
2906
2907 pub fn return_code(&self) -> Option<i64> {
2911 self.return_code
2912 }
2913
2914 pub fn meta(&self) -> &Object {
2916 &self.data.meta
2917 }
2918
2919 pub fn parameter_meta(&self) -> &Object {
2921 &self.data.parameter_meta
2922 }
2923
2924 pub fn ext(&self) -> &Object {
2926 &self.data.ext
2927 }
2928
2929 pub(crate) fn set_return_code(&mut self, code: i32) {
2931 self.return_code = Some(code as i64);
2932 }
2933
2934 pub(crate) fn set_attempt(&mut self, attempt: i64) {
2936 self.attempt = attempt;
2937 }
2938
2939 pub fn field(&self, name: &str) -> Option<Value> {
2943 match name {
2944 n if n == TASK_FIELD_NAME => {
2945 Some(PrimitiveValue::String(self.data.name.clone()).into())
2946 }
2947 n if n == TASK_FIELD_ID => Some(PrimitiveValue::String(self.data.id.clone()).into()),
2948 n if n == TASK_FIELD_CONTAINER => Some(
2949 self.data
2950 .container
2951 .clone()
2952 .map(|c| PrimitiveValue::String(c).into())
2953 .unwrap_or(Value::None),
2954 ),
2955 n if n == TASK_FIELD_CPU => Some(self.data.cpu.into()),
2956 n if n == TASK_FIELD_MEMORY => Some(self.data.memory.into()),
2957 n if n == TASK_FIELD_GPU => Some(self.data.gpu.clone().into()),
2958 n if n == TASK_FIELD_FPGA => Some(self.data.fpga.clone().into()),
2959 n if n == TASK_FIELD_DISKS => Some(self.data.disks.clone().into()),
2960 n if n == TASK_FIELD_ATTEMPT => Some(self.attempt.into()),
2961 n if n == TASK_FIELD_END_TIME => {
2962 Some(self.data.end_time.map(Into::into).unwrap_or(Value::None))
2963 }
2964 n if n == TASK_FIELD_RETURN_CODE => {
2965 Some(self.return_code.map(Into::into).unwrap_or(Value::None))
2966 }
2967 n if n == TASK_FIELD_META => Some(self.data.meta.clone().into()),
2968 n if n == TASK_FIELD_PARAMETER_META => Some(self.data.parameter_meta.clone().into()),
2969 n if n == TASK_FIELD_EXT => Some(self.data.ext.clone().into()),
2970 _ => None,
2971 }
2972 }
2973}
2974
2975#[derive(Debug, Clone)]
2979pub struct HintsValue(Object);
2980
2981impl HintsValue {
2982 pub fn as_object(&self) -> &Object {
2984 &self.0
2985 }
2986}
2987
2988impl fmt::Display for HintsValue {
2989 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2990 write!(f, "hints {{")?;
2991
2992 for (i, (k, v)) in self.0.iter().enumerate() {
2993 if i > 0 {
2994 write!(f, ", ")?;
2995 }
2996
2997 write!(f, "{k}: {v}")?;
2998 }
2999
3000 write!(f, "}}")
3001 }
3002}
3003
3004impl From<Object> for HintsValue {
3005 fn from(value: Object) -> Self {
3006 Self(value)
3007 }
3008}
3009
3010#[derive(Debug, Clone)]
3014pub struct InputValue(Object);
3015
3016impl InputValue {
3017 pub fn as_object(&self) -> &Object {
3019 &self.0
3020 }
3021}
3022
3023impl fmt::Display for InputValue {
3024 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3025 write!(f, "input {{")?;
3026
3027 for (i, (k, v)) in self.0.iter().enumerate() {
3028 if i > 0 {
3029 write!(f, ", ")?;
3030 }
3031
3032 write!(f, "{k}: {v}")?;
3033 }
3034
3035 write!(f, "}}")
3036 }
3037}
3038
3039impl From<Object> for InputValue {
3040 fn from(value: Object) -> Self {
3041 Self(value)
3042 }
3043}
3044
3045#[derive(Debug, Clone)]
3049pub struct OutputValue(Object);
3050
3051impl OutputValue {
3052 pub fn as_object(&self) -> &Object {
3054 &self.0
3055 }
3056}
3057
3058impl fmt::Display for OutputValue {
3059 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3060 write!(f, "output {{")?;
3061
3062 for (i, (k, v)) in self.0.iter().enumerate() {
3063 if i > 0 {
3064 write!(f, ", ")?;
3065 }
3066
3067 write!(f, "{k}: {v}")?;
3068 }
3069
3070 write!(f, "}}")
3071 }
3072}
3073
3074impl From<Object> for OutputValue {
3075 fn from(value: Object) -> Self {
3076 Self(value)
3077 }
3078}
3079
3080#[derive(Debug, Clone)]
3084pub struct CallValue {
3085 ty: CallType,
3087 outputs: Arc<Outputs>,
3089}
3090
3091impl CallValue {
3092 pub(crate) fn new_unchecked(ty: CallType, outputs: Arc<Outputs>) -> Self {
3095 Self { ty, outputs }
3096 }
3097
3098 pub fn ty(&self) -> &CallType {
3100 &self.ty
3101 }
3102
3103 pub fn outputs(&self) -> &Outputs {
3105 self.outputs.as_ref()
3106 }
3107}
3108
3109impl fmt::Display for CallValue {
3110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3111 write!(f, "call output {{")?;
3112
3113 for (i, (k, v)) in self.outputs.iter().enumerate() {
3114 if i > 0 {
3115 write!(f, ", ")?;
3116 }
3117
3118 write!(f, "{k}: {v}")?;
3119 }
3120
3121 write!(f, "}}")
3122 }
3123}
3124
3125#[cfg(test)]
3126mod test {
3127 use approx::assert_relative_eq;
3128 use pretty_assertions::assert_eq;
3129 use wdl_analysis::types::ArrayType;
3130 use wdl_analysis::types::MapType;
3131 use wdl_analysis::types::PairType;
3132 use wdl_analysis::types::StructType;
3133
3134 use super::*;
3135
3136 #[test]
3137 fn boolean_coercion() {
3138 assert_eq!(
3140 Value::from(false)
3141 .coerce(&PrimitiveType::Boolean.into())
3142 .expect("should coerce")
3143 .unwrap_boolean(),
3144 Value::from(false).unwrap_boolean()
3145 );
3146 assert_eq!(
3148 format!(
3149 "{e:?}",
3150 e = Value::from(true)
3151 .coerce(&PrimitiveType::String.into())
3152 .unwrap_err()
3153 ),
3154 "cannot coerce type `Boolean` to type `String`"
3155 );
3156 }
3157
3158 #[test]
3159 fn boolean_display() {
3160 assert_eq!(Value::from(false).to_string(), "false");
3161 assert_eq!(Value::from(true).to_string(), "true");
3162 }
3163
3164 #[test]
3165 fn integer_coercion() {
3166 assert_eq!(
3168 Value::from(12345)
3169 .coerce(&PrimitiveType::Integer.into())
3170 .expect("should coerce")
3171 .unwrap_integer(),
3172 Value::from(12345).unwrap_integer()
3173 );
3174 assert_relative_eq!(
3176 Value::from(12345)
3177 .coerce(&PrimitiveType::Float.into())
3178 .expect("should coerce")
3179 .unwrap_float(),
3180 Value::from(12345.0).unwrap_float()
3181 );
3182 assert_eq!(
3184 format!(
3185 "{e:?}",
3186 e = Value::from(12345)
3187 .coerce(&PrimitiveType::Boolean.into())
3188 .unwrap_err()
3189 ),
3190 "cannot coerce type `Int` to type `Boolean`"
3191 );
3192 }
3193
3194 #[test]
3195 fn integer_display() {
3196 assert_eq!(Value::from(12345).to_string(), "12345");
3197 assert_eq!(Value::from(-12345).to_string(), "-12345");
3198 }
3199
3200 #[test]
3201 fn float_coercion() {
3202 assert_relative_eq!(
3204 Value::from(12345.0)
3205 .coerce(&PrimitiveType::Float.into())
3206 .expect("should coerce")
3207 .unwrap_float(),
3208 Value::from(12345.0).unwrap_float()
3209 );
3210 assert_eq!(
3212 format!(
3213 "{e:?}",
3214 e = Value::from(12345.0)
3215 .coerce(&PrimitiveType::Integer.into())
3216 .unwrap_err()
3217 ),
3218 "cannot coerce type `Float` to type `Int`"
3219 );
3220 }
3221
3222 #[test]
3223 fn float_display() {
3224 assert_eq!(Value::from(12345.12345).to_string(), "12345.123450");
3225 assert_eq!(Value::from(-12345.12345).to_string(), "-12345.123450");
3226 }
3227
3228 #[test]
3229 fn string_coercion() {
3230 let value = PrimitiveValue::new_string("foo");
3231 assert_eq!(
3233 value
3234 .coerce(&PrimitiveType::String.into())
3235 .expect("should coerce"),
3236 value
3237 );
3238 assert_eq!(
3240 value
3241 .coerce(&PrimitiveType::File.into())
3242 .expect("should coerce"),
3243 PrimitiveValue::File(value.as_string().expect("should be string").clone())
3244 );
3245 assert_eq!(
3247 value
3248 .coerce(&PrimitiveType::Directory.into())
3249 .expect("should coerce"),
3250 PrimitiveValue::Directory(value.as_string().expect("should be string").clone())
3251 );
3252 assert_eq!(
3254 format!(
3255 "{e:?}",
3256 e = value.coerce(&PrimitiveType::Boolean.into()).unwrap_err()
3257 ),
3258 "cannot coerce type `String` to type `Boolean`"
3259 );
3260 }
3261
3262 #[test]
3263 fn string_display() {
3264 let value = PrimitiveValue::new_string("hello world!");
3265 assert_eq!(value.to_string(), "\"hello world!\"");
3266 }
3267
3268 #[test]
3269 fn file_coercion() {
3270 let value = PrimitiveValue::new_file("foo");
3271
3272 assert_eq!(
3274 value
3275 .coerce(&PrimitiveType::File.into())
3276 .expect("should coerce"),
3277 value
3278 );
3279 assert_eq!(
3281 value
3282 .coerce(&PrimitiveType::String.into())
3283 .expect("should coerce"),
3284 PrimitiveValue::String(value.as_file().expect("should be file").clone())
3285 );
3286 assert_eq!(
3288 format!(
3289 "{e:?}",
3290 e = value.coerce(&PrimitiveType::Directory.into()).unwrap_err()
3291 ),
3292 "cannot coerce type `File` to type `Directory`"
3293 );
3294 }
3295
3296 #[test]
3297 fn file_display() {
3298 let value = PrimitiveValue::new_file("/foo/bar/baz.txt");
3299 assert_eq!(value.to_string(), "\"/foo/bar/baz.txt\"");
3300 }
3301
3302 #[test]
3303 fn directory_coercion() {
3304 let value = PrimitiveValue::new_directory("foo");
3305
3306 assert_eq!(
3308 value
3309 .coerce(&PrimitiveType::Directory.into())
3310 .expect("should coerce"),
3311 value
3312 );
3313 assert_eq!(
3315 value
3316 .coerce(&PrimitiveType::String.into())
3317 .expect("should coerce"),
3318 PrimitiveValue::String(value.as_directory().expect("should be directory").clone())
3319 );
3320 assert_eq!(
3322 format!(
3323 "{e:?}",
3324 e = value.coerce(&PrimitiveType::File.into()).unwrap_err()
3325 ),
3326 "cannot coerce type `Directory` to type `File`"
3327 );
3328 }
3329
3330 #[test]
3331 fn directory_display() {
3332 let value = PrimitiveValue::new_directory("/foo/bar/baz");
3333 assert_eq!(value.to_string(), "\"/foo/bar/baz\"");
3334 }
3335
3336 #[test]
3337 fn none_coercion() {
3338 assert!(
3340 Value::None
3341 .coerce(&Type::from(PrimitiveType::String).optional())
3342 .expect("should coerce")
3343 .is_none(),
3344 );
3345
3346 assert_eq!(
3348 format!(
3349 "{e:?}",
3350 e = Value::None
3351 .coerce(&PrimitiveType::String.into())
3352 .unwrap_err()
3353 ),
3354 "cannot coerce `None` to non-optional type `String`"
3355 );
3356 }
3357
3358 #[test]
3359 fn none_display() {
3360 assert_eq!(Value::None.to_string(), "None");
3361 }
3362
3363 #[test]
3364 fn array_coercion() {
3365 let src_ty: Type = ArrayType::new(PrimitiveType::Integer).into();
3366 let target_ty: Type = ArrayType::new(PrimitiveType::Float).into();
3367
3368 let src: CompoundValue = Array::new(src_ty, [1, 2, 3])
3370 .expect("should create array value")
3371 .into();
3372 let target = src.coerce(&target_ty).expect("should coerce");
3373 assert_eq!(
3374 target.unwrap_array().to_string(),
3375 "[1.000000, 2.000000, 3.000000]"
3376 );
3377
3378 let target_ty: Type = ArrayType::new(PrimitiveType::String).into();
3380 assert_eq!(
3381 format!("{e:?}", e = src.coerce(&target_ty).unwrap_err()),
3382 r#"failed to coerce array element at index 0
3383
3384Caused by:
3385 cannot coerce type `Int` to type `String`"#
3386 );
3387 }
3388
3389 #[test]
3390 fn non_empty_array_coercion() {
3391 let ty: Type = ArrayType::new(PrimitiveType::String).into();
3392 let target_ty: Type = ArrayType::non_empty(PrimitiveType::String).into();
3393
3394 let string = PrimitiveValue::new_string("foo");
3396 let value: Value = Array::new(ty.clone(), [string])
3397 .expect("should create array")
3398 .into();
3399 assert!(value.coerce(&target_ty).is_ok(), "should coerce");
3400
3401 let value: Value = Array::new::<Value>(ty, [])
3403 .expect("should create array")
3404 .into();
3405 assert_eq!(
3406 format!("{e:?}", e = value.coerce(&target_ty).unwrap_err()),
3407 "cannot coerce empty array value to non-empty array type `Array[String]+`"
3408 );
3409 }
3410
3411 #[test]
3412 fn array_display() {
3413 let ty: Type = ArrayType::new(PrimitiveType::Integer).into();
3414 let value: Value = Array::new(ty, [1, 2, 3])
3415 .expect("should create array")
3416 .into();
3417
3418 assert_eq!(value.to_string(), "[1, 2, 3]");
3419 }
3420
3421 #[test]
3422 fn map_coerce() {
3423 let key1 = PrimitiveValue::new_file("foo");
3424 let value1 = PrimitiveValue::new_string("bar");
3425 let key2 = PrimitiveValue::new_file("baz");
3426 let value2 = PrimitiveValue::new_string("qux");
3427
3428 let ty = MapType::new(PrimitiveType::File, PrimitiveType::String);
3429 let value: Value = Map::new(ty, [(key1, value1), (key2, value2)])
3430 .expect("should create map value")
3431 .into();
3432
3433 let ty = MapType::new(PrimitiveType::String, PrimitiveType::File).into();
3435 let value = value.coerce(&ty).expect("value should coerce");
3436 assert_eq!(value.to_string(), r#"{"foo": "bar", "baz": "qux"}"#);
3437
3438 let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::File).into();
3440 assert_eq!(
3441 format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3442 r#"failed to coerce map key for element at index 0
3443
3444Caused by:
3445 cannot coerce type `String` to type `Int`"#
3446 );
3447
3448 let ty = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
3450 assert_eq!(
3451 format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3452 r#"failed to coerce map value for element at index 0
3453
3454Caused by:
3455 cannot coerce type `File` to type `Int`"#
3456 );
3457
3458 let ty = StructType::new(
3460 "Foo",
3461 [("foo", PrimitiveType::File), ("baz", PrimitiveType::File)],
3462 )
3463 .into();
3464 let struct_value = value.coerce(&ty).expect("value should coerce");
3465 assert_eq!(struct_value.to_string(), r#"Foo {foo: "bar", baz: "qux"}"#);
3466
3467 let ty = StructType::new(
3469 "Foo",
3470 [
3471 ("foo", PrimitiveType::File),
3472 ("baz", PrimitiveType::File),
3473 ("qux", PrimitiveType::File),
3474 ],
3475 )
3476 .into();
3477 assert_eq!(
3478 format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3479 "cannot coerce a map of 2 elements to struct type `Foo` as the struct has 3 members"
3480 );
3481
3482 let object_value = value.coerce(&Type::Object).expect("value should coerce");
3484 assert_eq!(
3485 object_value.to_string(),
3486 r#"object {foo: "bar", baz: "qux"}"#
3487 );
3488 }
3489
3490 #[test]
3491 fn map_display() {
3492 let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::Boolean);
3493 let value: Value = Map::new(ty, [(1, true), (2, false)])
3494 .expect("should create map value")
3495 .into();
3496 assert_eq!(value.to_string(), "{1: true, 2: false}");
3497 }
3498
3499 #[test]
3500 fn pair_coercion() {
3501 let left = PrimitiveValue::new_file("foo");
3502 let right = PrimitiveValue::new_string("bar");
3503
3504 let ty = PairType::new(PrimitiveType::File, PrimitiveType::String);
3505 let value: Value = Pair::new(ty, left, right)
3506 .expect("should create map value")
3507 .into();
3508
3509 let ty = PairType::new(PrimitiveType::String, PrimitiveType::File).into();
3511 let value = value.coerce(&ty).expect("value should coerce");
3512 assert_eq!(value.to_string(), r#"("foo", "bar")"#);
3513
3514 let ty = PairType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
3516 assert_eq!(
3517 format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3518 r#"failed to coerce pair's left value
3519
3520Caused by:
3521 cannot coerce type `String` to type `Int`"#
3522 );
3523 }
3524
3525 #[test]
3526 fn pair_display() {
3527 let ty = PairType::new(PrimitiveType::Integer, PrimitiveType::Boolean);
3528 let value: Value = Pair::new(ty, 12345, false)
3529 .expect("should create pair value")
3530 .into();
3531 assert_eq!(value.to_string(), "(12345, false)");
3532 }
3533
3534 #[test]
3535 fn struct_coercion() {
3536 let ty = StructType::new(
3537 "Foo",
3538 [
3539 ("foo", PrimitiveType::Float),
3540 ("bar", PrimitiveType::Float),
3541 ("baz", PrimitiveType::Float),
3542 ],
3543 );
3544 let value: Value = Struct::new(ty, [("foo", 1.0), ("bar", 2.0), ("baz", 3.0)])
3545 .expect("should create map value")
3546 .into();
3547
3548 let ty = MapType::new(PrimitiveType::String, PrimitiveType::Float).into();
3550 let map_value = value.coerce(&ty).expect("value should coerce");
3551 assert_eq!(
3552 map_value.to_string(),
3553 r#"{"foo": 1.000000, "bar": 2.000000, "baz": 3.000000}"#
3554 );
3555
3556 let ty = StructType::new(
3558 "Bar",
3559 [
3560 ("foo", PrimitiveType::Float),
3561 ("bar", PrimitiveType::Float),
3562 ("baz", PrimitiveType::Float),
3563 ],
3564 )
3565 .into();
3566 let struct_value = value.coerce(&ty).expect("value should coerce");
3567 assert_eq!(
3568 struct_value.to_string(),
3569 r#"Bar {foo: 1.000000, bar: 2.000000, baz: 3.000000}"#
3570 );
3571
3572 let object_value = value.coerce(&Type::Object).expect("value should coerce");
3574 assert_eq!(
3575 object_value.to_string(),
3576 r#"object {foo: 1.000000, bar: 2.000000, baz: 3.000000}"#
3577 );
3578 }
3579
3580 #[test]
3581 fn struct_display() {
3582 let ty = StructType::new(
3583 "Foo",
3584 [
3585 ("foo", PrimitiveType::Float),
3586 ("bar", PrimitiveType::String),
3587 ("baz", PrimitiveType::Integer),
3588 ],
3589 );
3590 let value: Value = Struct::new(
3591 ty,
3592 [
3593 ("foo", Value::from(1.101)),
3594 ("bar", PrimitiveValue::new_string("foo").into()),
3595 ("baz", 1234.into()),
3596 ],
3597 )
3598 .expect("should create map value")
3599 .into();
3600 assert_eq!(
3601 value.to_string(),
3602 r#"Foo {foo: 1.101000, bar: "foo", baz: 1234}"#
3603 );
3604 }
3605}