Skip to main content

lutra_bin/value/
mod.rs

1//! Generic value object
2//!
3//! [Value] can represent any value in the Lutra type system.
4//! It is essentially moving type information from compile time into runtime,
5//! which is why it not recommended to use in general.
6//!
7//! Use this only when you need dynamic types, i.e. data whose type cannot be
8//! determined at compile time.
9
10mod decode;
11mod encode;
12mod fold;
13mod print_source;
14
15pub use fold::ValueVisitor;
16
17use crate::{boxed, string, vec};
18
19use crate::ir;
20use crate::{Error, Result};
21
22/// Generic Lutra value object
23#[derive(Clone, Debug, PartialEq)]
24pub enum Value {
25    Prim8(u8),
26    Prim16(u16),
27    Prim32(u32),
28    Prim64(u64),
29
30    Tuple(vec::Vec<Value>),
31    Array(vec::Vec<Value>),
32    Enum(usize, boxed::Box<Value>),
33}
34
35impl Value {
36    pub fn unit() -> Value {
37        Value::Tuple(vec![])
38    }
39
40    pub fn expect_prim8(&self) -> Result<u8> {
41        match self {
42            Value::Prim8(value) => Ok(*value),
43            _ => Err(Error::BadValueType {
44                expected: "Prim8",
45                found: self.name(),
46            }),
47        }
48    }
49
50    pub fn expect_prim16(&self) -> Result<u16> {
51        match self {
52            Value::Prim16(value) => Ok(*value),
53            _ => Err(Error::BadValueType {
54                expected: "Prim16",
55                found: self.name(),
56            }),
57        }
58    }
59
60    pub fn expect_prim32(&self) -> Result<u32> {
61        match self {
62            Value::Prim32(value) => Ok(*value),
63            _ => Err(Error::BadValueType {
64                expected: "Prim32",
65                found: self.name(),
66            }),
67        }
68    }
69
70    pub fn expect_prim64(&self) -> Result<u64> {
71        match self {
72            Value::Prim64(value) => Ok(*value),
73            _ => Err(Error::BadValueType {
74                expected: "Prim64",
75                found: self.name(),
76            }),
77        }
78    }
79
80    pub fn new_text(s: &str) -> Value {
81        Value::Array(s.bytes().map(Value::Prim8).collect())
82    }
83
84    pub fn expect_text_cloned(&self) -> Result<string::String> {
85        match self {
86            Value::Array(bytes) => {
87                let bytes: vec::Vec<u8> = bytes
88                    .iter()
89                    .map(|v| v.expect_prim8())
90                    .collect::<Result<_>>()?;
91                string::String::from_utf8(bytes).map_err(|_| Error::InvalidData)
92            }
93            _ => Err(Error::BadValueType {
94                expected: "Text",
95                found: self.name(),
96            }),
97        }
98    }
99
100    pub fn expect_tuple(&self) -> Result<&[Value]> {
101        match self {
102            Value::Tuple(value) => Ok(value),
103            _ => Err(Error::BadValueType {
104                expected: "Tuple",
105                found: self.name(),
106            }),
107        }
108    }
109
110    pub fn expect_array(&self) -> Result<&[Value]> {
111        match self {
112            Value::Array(value) => Ok(value),
113            _ => Err(Error::BadValueType {
114                expected: "Array",
115                found: self.name(),
116            }),
117        }
118    }
119
120    pub fn expect_enum(&self) -> Result<(usize, &Value)> {
121        match self {
122            Value::Enum(tag, inner) => Ok((*tag, inner)),
123            _ => Err(Error::BadValueType {
124                expected: "Enum",
125                found: self.name(),
126            }),
127        }
128    }
129
130    fn name(&self) -> &'static str {
131        match self {
132            Value::Prim8(..) => "Prim8",
133            Value::Prim16(..) => "Prim16",
134            Value::Prim32(..) => "Prim32",
135            Value::Prim64(..) => "Prim64",
136            Value::Tuple(..) => "Tuple",
137            Value::Array(..) => "Array",
138            Value::Enum(..) => "Enum",
139        }
140    }
141}
142
143#[derive(Clone, Copy, Debug, PartialEq)]
144enum TyClass<'t> {
145    Prim8,
146    Prim16,
147    Prim32,
148    Prim64,
149    Tuple(&'t [ir::TyTupleField]),
150    Array(&'t ir::Ty),
151    Enum(&'t [ir::TyEnumVariant]),
152}
153
154impl<'t> TyClass<'t> {
155    fn of_ty(ty_mat: &'t ir::Ty) -> Result<Self> {
156        Ok(match &ty_mat.kind {
157            ir::TyKind::Primitive(ir::TyPrimitive::Prim8) => TyClass::Prim8,
158            ir::TyKind::Primitive(ir::TyPrimitive::Prim16) => TyClass::Prim16,
159            ir::TyKind::Primitive(ir::TyPrimitive::Prim32) => TyClass::Prim32,
160            ir::TyKind::Primitive(ir::TyPrimitive::Prim64) => TyClass::Prim64,
161
162            ir::TyKind::Tuple(t) => TyClass::Tuple(t),
163            ir::TyKind::Array(t) => TyClass::Array(t),
164            ir::TyKind::Enum(t) => TyClass::Enum(t),
165
166            ir::TyKind::Function(..) => return Err(Error::InvalidType),
167            ir::TyKind::Ident(..) => return Err(Error::Bug),
168        })
169    }
170}