Skip to main content

ruby_types/
lib.rs

1//! Ruby types for Rusty Ruby
2//!
3//! This crate provides core Ruby value and error types for the Rusty Ruby ecosystem.
4
5#![warn(missing_docs)]
6
7use serde::{Deserialize, Serialize};
8
9/// Ruby value type
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11pub enum RubyValue {
12    /// Nil value
13    Nil,
14    /// Boolean value
15    Boolean(bool),
16    /// Integer value
17    Integer(i32),
18    /// Float value
19    Float(f64),
20    /// String value
21    String(String),
22    /// Symbol value
23    Symbol(String),
24    /// Array value
25    Array(Vec<RubyValue>),
26    /// Hash value
27    Hash(std::collections::HashMap<String, RubyValue>),
28    /// Object value
29    Object(String, std::collections::HashMap<String, RubyValue>),
30    /// Closure value
31    Closure(usize), // 使用 usize 作为闭包的唯一标识符
32}
33
34impl RubyValue {
35    /// Check if value is nil
36    pub fn is_nil(&self) -> bool {
37        matches!(self, RubyValue::Nil)
38    }
39
40    /// Convert value to i32
41    pub fn to_i32(&self) -> i32 {
42        match self {
43            RubyValue::Integer(i) => *i,
44            RubyValue::Float(f) => *f as i32,
45            RubyValue::Boolean(b) => {
46                if *b {
47                    1
48                }
49                else {
50                    0
51                }
52            }
53            _ => 0,
54        }
55    }
56
57    /// Convert value to f64
58    pub fn to_f64(&self) -> f64 {
59        match self {
60            RubyValue::Float(f) => *f,
61            RubyValue::Integer(i) => *i as f64,
62            RubyValue::Boolean(b) => {
63                if *b {
64                    1.0
65                }
66                else {
67                    0.0
68                }
69            }
70            _ => 0.0,
71        }
72    }
73
74    /// Convert value to bool
75    pub fn to_bool(&self) -> bool {
76        match self {
77            RubyValue::Nil => false,
78            RubyValue::Boolean(b) => *b,
79            RubyValue::Integer(i) => *i != 0,
80            RubyValue::Float(f) => *f != 0.0,
81            _ => true,
82        }
83    }
84
85    /// Convert value to string
86    pub fn to_string(&self) -> String {
87        match self {
88            RubyValue::String(s) => s.clone(),
89            RubyValue::Symbol(s) => s.clone(),
90            RubyValue::Integer(i) => i.to_string(),
91            RubyValue::Float(f) => f.to_string(),
92            RubyValue::Boolean(b) => b.to_string(),
93            RubyValue::Nil => "nil".to_string(),
94            _ => format!("{:?}", self),
95        }
96    }
97
98    /// Mark this value and all referenced values
99    pub fn mark(&self, marked: &mut std::collections::HashSet<*const RubyValue>) {
100        let ptr = self as *const RubyValue;
101        if marked.contains(&ptr) {
102            return;
103        }
104        marked.insert(ptr);
105
106        match self {
107            RubyValue::Array(values) => {
108                for value in values {
109                    value.mark(marked);
110                }
111            }
112            RubyValue::Hash(map) => {
113                for (_, value) in map {
114                    value.mark(marked);
115                }
116            }
117            RubyValue::Object(_, fields) => {
118                for (_, value) in fields {
119                    value.mark(marked);
120                }
121            }
122            _ => {}
123        }
124    }
125
126    /// Concatenate two Ruby values
127    pub fn concat(&self, other: &RubyValue) -> RubyValue {
128        match (self, other) {
129            (RubyValue::String(s1), RubyValue::String(s2)) => RubyValue::String(format!("{}{}", s1, s2)),
130            (RubyValue::Array(arr1), RubyValue::Array(arr2)) => {
131                let mut result = arr1.clone();
132                result.extend(arr2.clone());
133                RubyValue::Array(result)
134            }
135            _ => RubyValue::String(format!("{}{}", self.to_string(), other.to_string())),
136        }
137    }
138
139    /// Get array length
140    pub fn array_length(&self) -> Option<usize> {
141        match self {
142            RubyValue::Array(arr) => Some(arr.len()),
143            _ => None,
144        }
145    }
146
147    /// Get array element at index
148    pub fn array_get(&self, index: usize) -> Option<RubyValue> {
149        match self {
150            RubyValue::Array(arr) => arr.get(index).cloned(),
151            _ => None,
152        }
153    }
154
155    /// Set array element at index
156    pub fn array_set(&mut self, index: usize, value: RubyValue) -> Option<()> {
157        match self {
158            RubyValue::Array(arr) => {
159                if index < arr.len() {
160                    arr[index] = value;
161                    Some(())
162                }
163                else {
164                    None
165                }
166            }
167            _ => None,
168        }
169    }
170
171    /// Get hash value for key
172    pub fn hash_get(&self, key: &str) -> Option<RubyValue> {
173        match self {
174            RubyValue::Hash(map) => map.get(key).cloned(),
175            _ => None,
176        }
177    }
178
179    /// Set hash value for key
180    pub fn hash_set(&mut self, key: &str, value: RubyValue) -> Option<()> {
181        match self {
182            RubyValue::Hash(map) => {
183                map.insert(key.to_string(), value);
184                Some(())
185            }
186            _ => None,
187        }
188    }
189
190    /// Get hash keys
191    pub fn hash_keys(&self) -> Option<Vec<String>> {
192        match self {
193            RubyValue::Hash(map) => Some(map.keys().cloned().collect()),
194            _ => None,
195        }
196    }
197
198    /// Get hash values
199    pub fn hash_values(&self) -> Option<Vec<RubyValue>> {
200        match self {
201            RubyValue::Hash(map) => Some(map.values().cloned().collect()),
202            _ => None,
203        }
204    }
205
206    /// Get object field
207    pub fn object_get(&self, field: &str) -> Option<RubyValue> {
208        match self {
209            RubyValue::Object(_, fields) => fields.get(field).cloned(),
210            _ => None,
211        }
212    }
213
214    /// Set object field
215    pub fn object_set(&mut self, field: &str, value: RubyValue) -> Option<()> {
216        match self {
217            RubyValue::Object(_, fields) => {
218                fields.insert(field.to_string(), value);
219                Some(())
220            }
221            _ => None,
222        }
223    }
224}
225
226/// Ruby error type
227#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
228pub enum RubyError {
229    /// Method not found error
230    MethodNotFound(String),
231    /// Class not found error
232    ClassNotFound(String),
233    /// Lexical analysis error
234    LexicalError(String),
235    /// Syntax analysis error
236    SyntaxError(String),
237    /// Runtime error
238    RuntimeError(String),
239    /// Type error
240    TypeError(String),
241    /// Argument error
242    ArgumentError(String),
243}
244
245impl std::fmt::Display for RubyError {
246    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
247        match self {
248            RubyError::MethodNotFound(name) => write!(f, "Method not found: {}", name),
249            RubyError::ClassNotFound(name) => write!(f, "Class not found: {}", name),
250            RubyError::LexicalError(msg) => write!(f, "Lexical error: {}", msg),
251            RubyError::SyntaxError(msg) => write!(f, "Syntax error: {}", msg),
252            RubyError::RuntimeError(msg) => write!(f, "Runtime error: {}", msg),
253            RubyError::TypeError(msg) => write!(f, "Type error: {}", msg),
254            RubyError::ArgumentError(msg) => write!(f, "Argument error: {}", msg),
255        }
256    }
257}
258
259impl std::error::Error for RubyError {}
260
261/// Ruby result type
262pub type RubyResult<T> = std::result::Result<T, RubyError>;