Skip to main content

lasm/
value.rs

1use std::default::Default;
2use std::fmt::Display;
3
4/// Represents a value that can be passed to or returned from a LASM function.
5#[derive(Clone, Debug, PartialEq)]
6pub enum Value {
7    Int(i64),
8    Float(f64),
9    /// A string value, high level, gets converted to a pointer when passed to the LASM function. String gets never returned.
10    String(String),
11    Ptr(*mut u8),
12    Null,
13}
14
15impl Into<Value> for i64 {
16    fn into(self) -> Value {
17        Value::Int(self)
18    }
19}
20
21impl Into<Value> for f64 {
22    fn into(self) -> Value {
23        Value::Float(self)
24    }
25}
26
27impl Into<Value> for String {
28    fn into(self) -> Value {
29        Value::String(self)
30    }
31}
32
33impl Into<Value> for *mut u8 {
34    fn into(self) -> Value {
35        Value::Ptr(self)
36    }
37}
38
39impl Default for Value {
40    fn default() -> Self {
41        Value::Null
42    }
43}
44
45impl Display for Value {
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        match self {
48            Value::Int(i) => write!(f, "{}", i),
49            Value::Float(fl) => write!(f, "{}", fl),
50            Value::String(s) => write!(f, "\"{}\"", s),
51            Value::Ptr(p) => write!(f, "Ptr({:p})", p),
52            Value::Null => write!(f, "Null"),
53        }
54    }
55}
56
57impl Value {
58    pub fn as_int(&self) -> Option<i64> {
59        match self {
60            Value::Int(i) => Some(*i),
61            _ => None,
62        }
63    }
64
65    pub fn as_float(&self) -> Option<f64> {
66        match self {
67            Value::Float(f) => Some(*f),
68            _ => None,
69        }
70    }
71
72    pub fn as_string(&self) -> Option<&str> {
73        match self {
74            Value::String(s) => Some(s),
75            _ => None,
76        }
77    }
78
79    pub fn as_ptr(&self) -> Option<*mut u8> {
80        match self {
81            Value::Ptr(p) => Some(*p),
82            _ => None,
83        }
84    }
85
86    pub fn to_str(&self) -> Value {
87        match self {
88            Value::Int(i) => {
89                if (0..=255).contains(i) {
90                    if let Some(c) = char::from_u32(*i as u32) {
91                        Value::String(c.to_string())
92                    } else {
93                        Value::String(i.to_string())
94                    }
95                } else {
96                    Value::String(i.to_string())
97                }
98            }
99            Value::Float(f) => {
100                let bits = f.to_bits() as i64;
101                if (0..=255).contains(&bits) {
102                    if let Some(c) = char::from_u32(bits as u32) {
103                        Value::String(c.to_string())
104                    } else {
105                        Value::String(f.to_string())
106                    }
107                } else {
108                    Value::String(f.to_string())
109                }
110            }
111            Value::String(s) => Value::String(s.clone()),
112            Value::Ptr(p) => {
113                use std::ffi::CStr;
114                unsafe {
115                    match CStr::from_ptr(*p as *const i8).to_str() {
116                        Ok(s) => Value::String(s.to_string()),
117                        Err(_) => Value::String("<invalid utf8>".to_string()),
118                    }
119                }
120            }
121            Value::Null => Value::String("null".to_string()),
122        }
123    }
124}