stack_assembly/value.rs
1use std::fmt;
2
3/// # A unit of data
4///
5/// StackAssembly is an _untyped_ languages. All of its values, both on the
6/// [`Stack`] and in [`Memory`], are 32 bits wide. Depending on the situation,
7/// they may be interpreted as unsigned or signed.
8///
9/// You can create an instance of `Value` through its `From` implementations.
10///
11/// ```
12/// use stack_assembly::Value;
13///
14/// Value::from(3i32);
15/// Value::from(5u32);
16/// ```
17///
18/// [`Stack`]: crate::Stack
19/// [`Memory`]: crate::Memory
20#[derive(Clone, Copy, Eq, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
21#[repr(transparent)]
22pub struct Value {
23 inner: u32,
24}
25
26impl Value {
27 /// # Convert the value to an `i32`
28 ///
29 /// Since all values are 32 bits wide, this is always possible. Interprets
30 /// the bits of the value as a signed (two's complement) integer.
31 pub fn to_i32(self) -> i32 {
32 i32::from_le_bytes(self.inner.to_le_bytes())
33 }
34
35 /// # Convert the value to a `u32`
36 ///
37 /// Since all values are 32 bits wide, this is always possible. Interprets
38 /// the bits of the value as an unsigned integer.
39 pub fn to_u32(self) -> u32 {
40 self.inner
41 }
42
43 /// # Convert to a `usize`
44 ///
45 /// This is usually possible, unless this library runs on a platform where
46 /// `usize` is less than 32 bits wide. That is considered a niche use case
47 /// which is not fully supported.
48 ///
49 /// ## Panics
50 ///
51 /// Panics, if `usize` can not represent this value.
52 pub fn to_usize(self) -> usize {
53 let Ok(index) = self.inner.try_into() else {
54 panic!(
55 "Can't convert value `{value}` to `usize`. This can only \
56 happen on platforms where Rust's `usize` is less than 32 bits \
57 bits wide. This is a niche use case that isn't fully \
58 supported, making this panic an acceptable outcome.\n\
59 \n\
60 Additionally, since `usize` is only used for storage of values \
61 or operators, the value was invalid in the first place \
62 (meaning the StackAssembly program has a bug), as it wouldn't \
63 be possible to store as many item as the value implies should \
64 be there.",
65 value = self.inner,
66 );
67 };
68
69 index
70 }
71}
72
73impl From<i32> for Value {
74 fn from(value: i32) -> Self {
75 let inner = u32::from_le_bytes(value.to_le_bytes());
76 Self { inner }
77 }
78}
79
80impl From<u32> for Value {
81 fn from(inner: u32) -> Self {
82 Self { inner }
83 }
84}
85
86impl fmt::Debug for Value {
87 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88 // Let's bypass this type and format the inner value. This is just a
89 // wrapper anyway, and showing it in debug output is unnecessary noise.
90 self.inner.fmt(f)
91 }
92}