Skip to main content

wdl_engine/
lib.rs

1//! Execution engine for Workflow Description Language (WDL) documents.
2
3use std::sync::LazyLock;
4
5use num_enum::IntoPrimitive;
6use sysinfo::CpuRefreshKind;
7use sysinfo::MemoryRefreshKind;
8use sysinfo::System;
9use wdl_analysis::Document;
10use wdl_analysis::diagnostics::unknown_type;
11use wdl_analysis::types::Type;
12use wdl_analysis::types::TypeNameResolver;
13use wdl_analysis::types::v1::AstTypeConverter;
14use wdl_ast::Diagnostic;
15use wdl_ast::Span;
16use wdl_ast::TreeNode;
17
18mod backend;
19mod cache;
20pub mod config;
21mod diagnostics;
22mod digest;
23mod eval;
24mod http;
25mod inputs;
26mod outputs;
27mod path;
28mod stdlib;
29mod tree;
30mod units;
31mod value;
32
33pub use config::Config;
34pub use eval::*;
35pub use inputs::*;
36pub use outputs::*;
37pub use path::*;
38use units::*;
39pub use value::*;
40
41use crate::cache::Hashable;
42
43/// One gibibyte (GiB) as a float.
44///
45/// This is defined as a constant as it's a commonly performed conversion.
46const ONE_GIBIBYTE: f64 = 1024.0 * 1024.0 * 1024.0;
47
48/// Resolves a type name from a document.
49///
50/// This function will import the type into the type cache if not already
51/// cached.
52fn resolve_type_name(document: &Document, name: &str, span: Span) -> Result<Type, Diagnostic> {
53    document
54        .struct_by_name(name)
55        .map(|s| s.ty().expect("struct should have type").clone())
56        .or_else(|| {
57            document
58                .enum_by_name(name)
59                .map(|e| e.ty().expect("enum should have type").clone())
60        })
61        .ok_or_else(|| unknown_type(name, span))
62}
63
64/// Converts a V1 AST type to an analysis type.
65fn convert_ast_type_v1<N: TreeNode>(
66    document: &Document,
67    ty: &wdl_ast::v1::Type<N>,
68) -> Result<Type, Diagnostic> {
69    /// Used to resolve a type name from a document.
70    struct Resolver<'a>(&'a Document);
71
72    impl TypeNameResolver for Resolver<'_> {
73        fn resolve(&mut self, name: &str, span: Span) -> Result<Type, Diagnostic> {
74            resolve_type_name(self.0, name, span)
75        }
76    }
77
78    AstTypeConverter::new(Resolver(document)).convert_type(ty)
79}
80
81/// Cached information about the host system.
82static SYSTEM: LazyLock<System> = LazyLock::new(|| {
83    let mut system = System::new();
84    system.refresh_cpu_list(CpuRefreshKind::nothing());
85    system.refresh_memory_specifics(MemoryRefreshKind::nothing().with_ram());
86    system
87});
88
89/// Represents either file or directory content.
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IntoPrimitive)]
91#[repr(u8)]
92enum ContentKind {
93    /// The content is a single file.
94    File,
95    /// The content is a directory.
96    Directory,
97}
98
99impl Hashable for ContentKind {
100    fn hash(&self, hasher: &mut blake3::Hasher) {
101        hasher.update(&[(*self).into()]);
102    }
103}
104
105impl From<ContentKind> for crankshaft::engine::task::input::Type {
106    fn from(value: ContentKind) -> Self {
107        match value {
108            ContentKind::File => Self::File,
109            ContentKind::Directory => Self::Directory,
110        }
111    }
112}