Skip to main content

harn_kernel/execution/
runtime_value.rs

1use std::collections::BTreeMap;
2use std::rc::{Rc, Weak};
3use std::sync::Arc;
4
5use super::resource::validate_runtime_value;
6use super::{diagnostic, DataValue, Env};
7use crate::value::{SemanticValue, ValueView};
8use crate::{CompiledFunction, Constant, Diagnostic};
9
10#[derive(Clone)]
11pub(super) struct Closure {
12    pub(super) function: Arc<CompiledFunction>,
13    pub(super) env: Weak<Env>,
14}
15
16#[derive(Clone)]
17pub(super) struct EnumValue {
18    pub(super) enum_name: Arc<str>,
19    pub(super) variant: Arc<str>,
20    pub(super) fields: Rc<Vec<RuntimeValue>>,
21}
22
23impl EnumValue {
24    pub(super) fn is_variant(&self, enum_name: &str, variant: &str) -> bool {
25        self.enum_name.as_ref() == enum_name && self.variant.as_ref() == variant
26    }
27}
28
29#[derive(Clone)]
30pub(super) enum RuntimeValue {
31    Nil,
32    Bool(bool),
33    Int(i64),
34    Float(f64),
35    String(Arc<str>),
36    Bytes(Arc<[u8]>),
37    List(Rc<Vec<RuntimeValue>>),
38    Record(Rc<BTreeMap<String, RuntimeValue>>),
39    Enum(Rc<EnumValue>),
40    Closure(Closure),
41    Builtin(String),
42    Harness(String),
43}
44
45impl RuntimeValue {
46    pub(super) fn truthy(&self) -> bool {
47        match self {
48            Self::Nil | Self::Bool(false) => false,
49            Self::Int(0) => false,
50            Self::Float(value) if *value == 0.0 || value.is_nan() => false,
51            Self::String(value) => !value.is_empty(),
52            Self::List(value) => !value.is_empty(),
53            Self::Record(value) => !value.is_empty(),
54            _ => true,
55        }
56    }
57
58    pub(super) fn display(&self) -> String {
59        match self {
60            Self::Nil => "nil".into(),
61            Self::Bool(value) => value.to_string(),
62            Self::Int(value) => value.to_string(),
63            Self::Float(value) => value.to_string(),
64            Self::String(value) => value.to_string(),
65            Self::Bytes(value) => format!("<{} bytes>", value.len()),
66            Self::List(values) => format!(
67                "[{}]",
68                values
69                    .iter()
70                    .map(Self::display)
71                    .collect::<Vec<_>>()
72                    .join(", ")
73            ),
74            Self::Record(values) => format!(
75                "{{{}}}",
76                values
77                    .iter()
78                    .map(|(key, value)| format!("{key}: {}", value.display()))
79                    .collect::<Vec<_>>()
80                    .join(", ")
81            ),
82            Self::Enum(value) if value.fields.is_empty() => {
83                format!("{}.{}", value.enum_name, value.variant)
84            }
85            Self::Enum(value) => format!(
86                "{}.{}({})",
87                value.enum_name,
88                value.variant,
89                value
90                    .fields
91                    .iter()
92                    .map(Self::display)
93                    .collect::<Vec<_>>()
94                    .join(", ")
95            ),
96            Self::Closure(_) => "<closure>".into(),
97            Self::Builtin(name) => format!("<builtin {name}>"),
98            Self::Harness(name) => format!("<harness {name}>"),
99        }
100    }
101}
102
103impl SemanticValue for RuntimeValue {
104    fn semantic_view(&self) -> ValueView<'_, Self> {
105        match self {
106            Self::Nil => ValueView::Nil,
107            Self::Bool(value) => ValueView::Bool(*value),
108            Self::Int(value) => ValueView::Int(*value),
109            Self::Float(value) => ValueView::Float(*value),
110            Self::String(value) => ValueView::String(value),
111            Self::Bytes(value) => ValueView::Bytes(value),
112            Self::List(values) => ValueView::List(values),
113            Self::Record(values) => ValueView::Record(values),
114            Self::Enum(value) => ValueView::Enum {
115                enum_name: &value.enum_name,
116                variant: &value.variant,
117                fields: &value.fields,
118            },
119            Self::Closure(_) | Self::Builtin(_) | Self::Harness(_) => ValueView::Opaque,
120        }
121    }
122}
123
124impl From<DataValue> for RuntimeValue {
125    fn from(value: DataValue) -> Self {
126        match value {
127            DataValue::Nil => Self::Nil,
128            DataValue::Bool(value) => Self::Bool(value),
129            DataValue::Int(value) => Self::Int(value),
130            DataValue::Float(value) => Self::Float(value),
131            DataValue::String(value) => Self::String(Arc::from(value)),
132            DataValue::Bytes(value) => Self::Bytes(Arc::from(value)),
133            DataValue::List(values) => {
134                Self::List(Rc::new(values.into_iter().map(Self::from).collect()))
135            }
136            DataValue::Record(values) => Self::Record(Rc::new(
137                values
138                    .into_iter()
139                    .map(|(key, value)| (key, Self::from(value)))
140                    .collect(),
141            )),
142        }
143    }
144}
145
146impl From<Constant> for RuntimeValue {
147    fn from(value: Constant) -> Self {
148        match value {
149            Constant::Int(value) => Self::Int(value),
150            Constant::Float(value) => Self::Float(value),
151            Constant::String(value) => Self::String(Arc::from(value)),
152            Constant::Bool(value) => Self::Bool(value),
153            Constant::Nil => Self::Nil,
154            Constant::Duration(value) => Self::Int(value),
155        }
156    }
157}
158
159impl TryFrom<RuntimeValue> for DataValue {
160    type Error = Diagnostic;
161
162    fn try_from(value: RuntimeValue) -> Result<Self, Self::Error> {
163        validate_runtime_value(&value)?;
164        Self::try_from_validated(value)
165    }
166}
167
168impl DataValue {
169    fn try_from_validated(value: RuntimeValue) -> Result<Self, Diagnostic> {
170        Ok(match value {
171            RuntimeValue::Nil => Self::Nil,
172            RuntimeValue::Bool(value) => Self::Bool(value),
173            RuntimeValue::Int(value) => Self::Int(value),
174            RuntimeValue::Float(value) => Self::Float(value),
175            RuntimeValue::String(value) => Self::String(value.to_string()),
176            RuntimeValue::Bytes(value) => Self::Bytes(value.to_vec()),
177            RuntimeValue::List(values) => Self::List(
178                Rc::unwrap_or_clone(values)
179                    .into_iter()
180                    .map(Self::try_from_validated)
181                    .collect::<Result<_, _>>()?,
182            ),
183            RuntimeValue::Record(values) => Self::Record(
184                Rc::unwrap_or_clone(values)
185                    .into_iter()
186                    .map(|(key, value)| Ok((key, Self::try_from_validated(value)?)))
187                    .collect::<Result<_, Diagnostic>>()?,
188            ),
189            RuntimeValue::Enum(_) => {
190                return Err(diagnostic(
191                    "non_data_result",
192                    "execution returned an enum outside the portable data contract",
193                ));
194            }
195            RuntimeValue::Closure(_) | RuntimeValue::Builtin(_) | RuntimeValue::Harness(_) => {
196                return Err(diagnostic(
197                    "non_data_result",
198                    "execution returned a host or callable value",
199                ));
200            }
201        })
202    }
203}