Skip to main content

nifty_interp/
value.rs

1//! Runtime values. Lists and structs share their contents until one copy is changed, so
2//! passing them around is cheap while keeping value semantics.
3
4use std::fmt;
5use std::rc::Rc;
6
7#[derive(Clone, Debug, PartialEq)]
8pub enum Value {
9    Int(i64),
10    Float(f64),
11    Bool(bool),
12    String(Rc<str>),
13    List(Rc<Vec<Value>>),
14    Struct(Rc<Vec<Value>>),
15    Void,
16}
17
18impl Value {
19    /// A `[string]` of `texts`, in order.
20    pub(crate) fn strings(texts: Vec<String>) -> Self {
21        Self::List(Rc::new(
22            texts
23                .into_iter()
24                .map(|text| Self::String(Rc::from(text)))
25                .collect(),
26        ))
27    }
28
29    /// # Panics
30    /// When the value is not an `int`; the checker rules that out.
31    #[must_use]
32    pub fn as_int(&self) -> i64 {
33        match self {
34            Self::Int(value) => *value,
35            other => panic!("checked code produced {other:?} where an int was expected"),
36        }
37    }
38
39    /// # Panics
40    /// When the value is not a `bool`; the checker rules that out.
41    #[must_use]
42    pub fn as_bool(&self) -> bool {
43        match self {
44            Self::Bool(value) => *value,
45            other => panic!("checked code produced {other:?} where a bool was expected"),
46        }
47    }
48
49    /// # Panics
50    /// When the value is not a `string`; the checker rules that out.
51    #[must_use]
52    pub fn as_str(&self) -> &str {
53        match self {
54            Self::String(value) => value,
55            other => panic!("checked code produced {other:?} where a string was expected"),
56        }
57    }
58
59    /// The texts of a `[string]`, in order.
60    ///
61    /// # Panics
62    /// When the value is not a `[string]`; the checker rules that out.
63    #[must_use]
64    pub fn as_strs(&self) -> Vec<&str> {
65        match self {
66            Self::List(items) => items.iter().map(Self::as_str).collect(),
67            other => panic!("checked code produced {other:?} where a [string] was expected"),
68        }
69    }
70}
71
72/// How a value reads inside an interpolated string.
73impl fmt::Display for Value {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        match self {
76            Self::Int(value) => write!(f, "{value}"),
77            Self::Float(value) => write!(f, "{value}"),
78            Self::Bool(value) => write!(f, "{value}"),
79            Self::String(value) => f.write_str(value),
80            Self::List(items) | Self::Struct(items) => {
81                f.write_str("[")?;
82                for (index, item) in items.iter().enumerate() {
83                    if index > 0 {
84                        f.write_str(", ")?;
85                    }
86                    write!(f, "{item}")?;
87                }
88                f.write_str("]")
89            }
90            Self::Void => Ok(()),
91        }
92    }
93}