uni_core/primitives/
i16_ref.rs

1// RUST CONCEPT: I16 buffer indexed read primitive
2// Get the value at a specific index in an i16 buffer
3use crate::compat::{format, ToString};
4use crate::interpreter::Interpreter;
5use crate::value::{RuntimeError, Value};
6
7// RUST CONCEPT: i16-ref primitive
8// Stack: ( buffer index -- value )
9// Gets the i16 value at the specified index
10pub fn i16_ref_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
11    let index = interp.pop_integer()?;
12    let buffer_val = interp.pop()?;
13
14    match buffer_val {
15        Value::I16Buffer(buffer) => {
16            let borrowed = buffer.borrow();
17
18            if index >= borrowed.len() {
19                return Err(RuntimeError::DomainError(format!(
20                    "Index {} out of bounds for buffer of length {}",
21                    index,
22                    borrowed.len()
23                )));
24            }
25
26            let value = borrowed[index];
27            // Convert i16 to Int32 for consistency with other numeric types
28            interp.push(Value::Int32(value as i32));
29            Ok(())
30        }
31        _ => Err(RuntimeError::TypeError(
32            "i16-ref expects an i16-buffer".to_string(),
33        )),
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40    use crate::compat::Rc;
41
42    #[cfg(not(target_os = "none"))]
43    use std::cell::RefCell;
44    #[cfg(target_os = "none")]
45    use core::cell::RefCell;
46
47    fn setup_interpreter() -> Interpreter {
48        Interpreter::new()
49    }
50
51    #[test]
52    fn test_i16_ref_basic() {
53        let mut interp = setup_interpreter();
54
55        // Create a buffer with some values
56        let buffer = vec![10i16, 20, 30, 40, 50];
57        let buffer_val = Value::I16Buffer(Rc::new(RefCell::new(buffer)));
58
59        // Get value at index 2 (should be 30)
60        interp.push(buffer_val);
61        interp.push(Value::Int32(2));
62        let result = i16_ref_builtin(&mut interp);
63        assert!(result.is_ok());
64
65        let value = interp.pop().unwrap();
66        assert!(matches!(value, Value::Int32(30)));
67    }
68
69    #[test]
70    fn test_i16_ref_first_element() {
71        let mut interp = setup_interpreter();
72
73        let buffer = vec![100i16, 200, 300];
74        let buffer_val = Value::I16Buffer(Rc::new(RefCell::new(buffer)));
75
76        interp.push(buffer_val);
77        interp.push(Value::Int32(0));
78        i16_ref_builtin(&mut interp).unwrap();
79
80        let value = interp.pop().unwrap();
81        assert!(matches!(value, Value::Int32(100)));
82    }
83
84    #[test]
85    fn test_i16_ref_last_element() {
86        let mut interp = setup_interpreter();
87
88        let buffer = vec![10i16, 20, 30];
89        let buffer_val = Value::I16Buffer(Rc::new(RefCell::new(buffer)));
90
91        interp.push(buffer_val);
92        interp.push(Value::Int32(2));
93        i16_ref_builtin(&mut interp).unwrap();
94
95        let value = interp.pop().unwrap();
96        assert!(matches!(value, Value::Int32(30)));
97    }
98
99    #[test]
100    fn test_i16_ref_out_of_bounds() {
101        let mut interp = setup_interpreter();
102
103        let buffer = vec![10i16, 20, 30];
104        let buffer_val = Value::I16Buffer(Rc::new(RefCell::new(buffer)));
105
106        interp.push(buffer_val);
107        interp.push(Value::Int32(5));
108        let result = i16_ref_builtin(&mut interp);
109        assert!(matches!(result, Err(RuntimeError::DomainError(_))));
110    }
111
112    #[test]
113    fn test_i16_ref_negative_values() {
114        let mut interp = setup_interpreter();
115
116        let buffer = vec![-100i16, -200, -300];
117        let buffer_val = Value::I16Buffer(Rc::new(RefCell::new(buffer)));
118
119        interp.push(buffer_val);
120        interp.push(Value::Int32(1));
121        i16_ref_builtin(&mut interp).unwrap();
122
123        let value = interp.pop().unwrap();
124        assert!(matches!(value, Value::Int32(-200)));
125    }
126
127    #[test]
128    fn test_i16_ref_type_error() {
129        let mut interp = setup_interpreter();
130
131        // Try with non-buffer value
132        interp.push(Value::Number(42.0));
133        interp.push(Value::Int32(0));
134        let result = i16_ref_builtin(&mut interp);
135        assert!(matches!(result, Err(RuntimeError::TypeError(_))));
136    }
137
138    #[test]
139    fn test_i16_ref_stack_underflow() {
140        let mut interp = setup_interpreter();
141
142        // No values on stack
143        let result = i16_ref_builtin(&mut interp);
144        assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
145    }
146}