moco_vm/
value.rs

1use crate::{Integer, cons::Cons};
2use core::fmt::Debug;
3
4/// A value.
5pub trait Value: Clone + Copy + Default + PartialEq + Eq + PartialOrd + Ord {
6    /// A number.
7    type Number: Integer;
8
9    /// A pointer.
10    type Pointer: Integer;
11
12    /// Converts a number to a value.
13    fn from_number(number: Self::Number) -> Self;
14
15    /// Converts a value to a number.
16    fn to_number(self) -> Self::Number;
17
18    /// Converts a pointer to a value.
19    fn from_pointer(cons: Self::Pointer) -> Self;
20
21    /// Converts a value to a pointer.
22    fn to_pointer(self) -> Self::Pointer;
23
24    /// Checks if a value is a pointer.
25    fn is_pointer(self) -> bool;
26
27    /// Marks a value.
28    fn mark(self, mark: bool) -> Self;
29
30    /// Returns `true` if a value is marked.
31    fn is_marked(self) -> bool;
32
33    /// Converts a value to a cons.
34    fn to_cons(self) -> Cons<Self> {
35        Cons::new(self)
36    }
37
38    /// Converts a value to a cons.
39    fn from_cons(cons: Cons<Self>) -> Self {
40        cons.to_value()
41    }
42}
43
44/// A 16-bit value.
45#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
46pub struct Value16(u16);
47
48/// A 32-bit value.
49#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
50pub struct Value32(u32);
51
52/// A 64-bit value.
53#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
54pub struct Value64(u64);
55
56macro_rules! impl_value {
57    ($value:ty, $number:ty, $pointer:ty) => {
58        impl Value for $value {
59            type Number = $number;
60            type Pointer = $pointer;
61
62            #[inline]
63            fn from_number(number: Self::Number) -> Self {
64                Self(((number << 2) | 1) as _)
65            }
66
67            #[inline]
68            fn to_number(self) -> Self::Number {
69                self.0 as Self::Number >> 2
70            }
71
72            #[inline]
73            fn from_pointer(pointer: Self::Pointer) -> Self {
74                Self(pointer << 2)
75            }
76
77            #[inline]
78            fn to_pointer(self) -> Self::Pointer {
79                self.0 >> 2
80            }
81
82            #[inline]
83            fn is_pointer(self) -> bool {
84                self.0 & 1 == 0
85            }
86
87            #[inline]
88            fn mark(self, mark: bool) -> Self {
89                Self(if mark { self.0 | 0b10 } else { self.0 & !0b10 })
90            }
91
92            #[inline]
93            fn is_marked(self) -> bool {
94                self.0 & 0b10 != 0
95            }
96        }
97    };
98}
99
100impl_value!(Value16, i16, u16);
101impl_value!(Value32, i32, u32);
102impl_value!(Value64, i64, u64);
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107
108    macro_rules! test_value {
109        ($name:ident, $value:ty) => {
110            mod $name {
111                use super::*;
112                use core::mem::size_of;
113
114                fn from_number(number: <$value as Value>::Number) -> $value {
115                    <$value as Value>::from_number(number)
116                }
117
118                fn from_pointer(pointer: <$value as Value>::Pointer) -> $value {
119                    <$value as Value>::from_pointer(pointer)
120                }
121
122                #[test]
123                fn size() {
124                    assert_eq!(
125                        size_of::<<$value as Value>::Number>(),
126                        size_of::<<$value as Value>::Pointer>()
127                    );
128                }
129
130                #[test]
131                fn convert_number() {
132                    assert_eq!(from_number(-42).to_number(), -42);
133                    assert_eq!(from_number(-1).to_number(), -1);
134                    assert_eq!(from_number(0).to_number(), 0);
135                    assert_eq!(from_number(1).to_number(), 1);
136                    assert_eq!(from_number(42).to_number(), 42);
137                }
138
139                #[test]
140                fn convert_pointer() {
141                    assert_eq!(from_pointer(0).to_pointer(), 0);
142                    assert_eq!(from_pointer(1).to_pointer(), 1);
143                    assert_eq!(from_pointer(42).to_pointer(), 42);
144                }
145
146                #[test]
147                fn check_pointer() {
148                    assert!(from_pointer(0).is_pointer());
149                    assert!(!from_number(0).is_pointer());
150                }
151
152                #[test]
153                fn is_marked() {
154                    assert!(!from_pointer(0).is_marked());
155                    assert!(!from_number(0).is_marked());
156                }
157
158                #[test]
159                fn mark_number() {
160                    assert!(!from_number(0).mark(false).is_marked());
161                    assert!(from_number(0).mark(true).is_marked());
162                    assert_eq!(from_number(0).mark(false).to_number(), 0);
163                    assert_eq!(from_number(42).mark(false).to_number(), 42);
164                    assert_eq!(from_number(-42).mark(false).to_number(), -42);
165                    assert_eq!(from_number(0).mark(true).to_number(), 0);
166                    assert_eq!(from_number(42).mark(true).to_number(), 42);
167                    assert_eq!(from_number(-42).mark(true).to_number(), -42);
168                }
169
170                #[test]
171                fn mark_pointer() {
172                    assert!(!from_pointer(0).mark(false).is_marked());
173                    assert!(from_pointer(0).mark(true).is_marked());
174
175                    assert_eq!(from_pointer(0).mark(false).to_pointer(), 0);
176                    assert_eq!(from_pointer(42).mark(false).to_pointer(), 42);
177                    assert_eq!(from_pointer(0).mark(true).to_pointer(), 0);
178                    assert_eq!(from_pointer(42).mark(true).to_pointer(), 42);
179                }
180            }
181        };
182    }
183
184    test_value!(value16, Value16);
185    test_value!(value32, Value32);
186    test_value!(value64, Value64);
187}