Skip to main content

python_types/
lib.rs

1//! Python types for Rusty Python
2//!
3//! This crate provides core Python value and error types for the Rusty Python ecosystem.
4
5#![warn(missing_docs)]
6
7use std::sync::Arc;
8
9/// Python value type
10#[derive(Debug, Clone, PartialEq)]
11pub enum PythonValue {
12    /// None value
13    None,
14    /// Boolean value
15    Boolean(bool),
16    /// Integer value
17    Integer(i64),
18    /// Float value
19    Float(f64),
20    /// String value
21    String(String),
22    /// List value
23    List(Vec<Arc<PythonValue>>),
24    /// Tuple value
25    Tuple(Vec<Arc<PythonValue>>),
26    /// Dict value
27    Dict(std::collections::HashMap<String, Arc<PythonValue>>),
28    /// Object value
29    Object(String, std::collections::HashMap<String, Arc<PythonValue>>),
30    /// Function value
31    Function(String),
32}
33
34impl PythonValue {
35    /// Check if value is None
36    pub fn is_none(&self) -> bool {
37        matches!(self, PythonValue::None)
38    }
39
40    /// Convert value to i64
41    pub fn to_i64(&self) -> i64 {
42        match self {
43            PythonValue::Integer(i) => *i,
44            PythonValue::Float(f) => *f as i64,
45            PythonValue::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            PythonValue::Float(f) => *f,
61            PythonValue::Integer(i) => *i as f64,
62            PythonValue::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            PythonValue::None => false,
78            PythonValue::Boolean(b) => *b,
79            PythonValue::Integer(i) => *i != 0,
80            PythonValue::Float(f) => *f != 0.0,
81            PythonValue::String(s) => !s.is_empty(),
82            PythonValue::List(l) => !l.is_empty(),
83            PythonValue::Tuple(t) => !t.is_empty(),
84            PythonValue::Dict(d) => !d.is_empty(),
85            _ => true,
86        }
87    }
88
89    /// Convert value to string
90    pub fn to_string(&self) -> String {
91        match self {
92            PythonValue::String(s) => s.clone(),
93            PythonValue::Integer(i) => i.to_string(),
94            PythonValue::Float(f) => f.to_string(),
95            PythonValue::Boolean(b) => b.to_string(),
96            PythonValue::None => "None".to_string(),
97            PythonValue::List(l) => format!("{:?}", l),
98            PythonValue::Tuple(t) => format!("{:?}", t),
99            PythonValue::Dict(d) => format!("{:?}", d),
100            PythonValue::Object(name, _) => format!("<{} object>", name),
101            PythonValue::Function(name) => format!("<function {}>", name),
102        }
103    }
104
105    /// Get length of collection
106    pub fn len(&self) -> usize {
107        match self {
108            PythonValue::List(l) => l.len(),
109            PythonValue::Tuple(t) => t.len(),
110            PythonValue::Dict(d) => d.len(),
111            PythonValue::String(s) => s.len(),
112            _ => 0,
113        }
114    }
115
116    /// Get item from collection
117    pub fn get_item(&self, index: &PythonValue) -> PythonResult<Arc<PythonValue>> {
118        match (self, index) {
119            (PythonValue::List(l), PythonValue::Integer(i)) => {
120                let idx = *i as usize;
121                if idx < l.len() {
122                    Ok(l[idx].clone())
123                }
124                else {
125                    Err(PythonError::IndexError(format!("list index out of range: {}", i)))
126                }
127            }
128            (PythonValue::Tuple(t), PythonValue::Integer(i)) => {
129                let idx = *i as usize;
130                if idx < t.len() {
131                    Ok(t[idx].clone())
132                }
133                else {
134                    Err(PythonError::IndexError(format!("tuple index out of range: {}", i)))
135                }
136            }
137            (PythonValue::Dict(d), PythonValue::String(key)) => {
138                if let Some(value) = d.get(key) {
139                    Ok(value.clone())
140                }
141                else {
142                    Err(PythonError::KeyError(key.clone()))
143                }
144            }
145            (PythonValue::String(s), PythonValue::Integer(i)) => {
146                let idx = *i as usize;
147                if idx < s.len() {
148                    Ok(Arc::new(PythonValue::String(s.chars().nth(idx).unwrap().to_string())))
149                }
150                else {
151                    Err(PythonError::IndexError(format!("string index out of range: {}", i)))
152                }
153            }
154            _ => Err(PythonError::TypeError("unsupported operand type(s) for []".to_string())),
155        }
156    }
157
158    /// Set item in collection
159    pub fn set_item(&mut self, index: &PythonValue, value: Arc<PythonValue>) -> PythonResult<()> {
160        match (self, index) {
161            (PythonValue::List(l), PythonValue::Integer(i)) => {
162                let idx = *i as usize;
163                if idx < l.len() {
164                    l[idx] = value;
165                    Ok(())
166                }
167                else {
168                    Err(PythonError::IndexError(format!("list assignment index out of range: {}", i)))
169                }
170            }
171            (PythonValue::Dict(d), PythonValue::String(key)) => {
172                d.insert(key.clone(), value);
173                Ok(())
174            }
175            _ => Err(PythonError::TypeError("unsupported assignment to type".to_string())),
176        }
177    }
178
179    /// Append item to list
180    pub fn append(&mut self, value: Arc<PythonValue>) -> PythonResult<()> {
181        match self {
182            PythonValue::List(l) => {
183                l.push(value);
184                Ok(())
185            }
186            _ => Err(PythonError::TypeError("append() takes exactly one argument (0 given)".to_string())),
187        }
188    }
189
190    /// Add two values
191    pub fn add(&self, other: &PythonValue) -> PythonResult<PythonValue> {
192        match (self, other) {
193            (PythonValue::Integer(a), PythonValue::Integer(b)) => Ok(PythonValue::Integer(a + b)),
194            (PythonValue::Integer(a), PythonValue::Float(b)) => Ok(PythonValue::Float((*a as f64) + *b)),
195            (PythonValue::Float(a), PythonValue::Integer(b)) => Ok(PythonValue::Float(*a + (*b as f64))),
196            (PythonValue::Float(a), PythonValue::Float(b)) => Ok(PythonValue::Float(*a + *b)),
197            (PythonValue::String(a), PythonValue::String(b)) => Ok(PythonValue::String(format!("{}{}", a, b))),
198            (PythonValue::List(a), PythonValue::List(b)) => {
199                let mut result = a.clone();
200                result.extend(b.clone());
201                Ok(PythonValue::List(result))
202            }
203            (PythonValue::Tuple(a), PythonValue::Tuple(b)) => {
204                let mut result = a.clone();
205                result.extend(b.clone());
206                Ok(PythonValue::Tuple(result))
207            }
208            _ => Err(PythonError::TypeError("unsupported operand type(s) for +".to_string())),
209        }
210    }
211
212    /// Subtract two values
213    pub fn sub(&self, other: &PythonValue) -> PythonResult<PythonValue> {
214        match (self, other) {
215            (PythonValue::Integer(a), PythonValue::Integer(b)) => Ok(PythonValue::Integer(a - b)),
216            (PythonValue::Integer(a), PythonValue::Float(b)) => Ok(PythonValue::Float((*a as f64) - *b)),
217            (PythonValue::Float(a), PythonValue::Integer(b)) => Ok(PythonValue::Float(*a - (*b as f64))),
218            (PythonValue::Float(a), PythonValue::Float(b)) => Ok(PythonValue::Float(*a - *b)),
219            _ => Err(PythonError::TypeError("unsupported operand type(s) for -".to_string())),
220        }
221    }
222
223    /// Multiply two values
224    pub fn mul(&self, other: &PythonValue) -> PythonResult<PythonValue> {
225        match (self, other) {
226            (PythonValue::Integer(a), PythonValue::Integer(b)) => Ok(PythonValue::Integer(a * b)),
227            (PythonValue::Integer(a), PythonValue::Float(b)) => Ok(PythonValue::Float((*a as f64) * *b)),
228            (PythonValue::Float(a), PythonValue::Integer(b)) => Ok(PythonValue::Float(*a * (*b as f64))),
229            (PythonValue::Float(a), PythonValue::Float(b)) => Ok(PythonValue::Float(*a * *b)),
230            (PythonValue::String(a), PythonValue::Integer(b)) => {
231                if *b >= 0 {
232                    Ok(PythonValue::String(a.repeat(*b as usize)))
233                }
234                else {
235                    Ok(PythonValue::String("".to_string()))
236                }
237            }
238            (PythonValue::List(a), PythonValue::Integer(b)) => {
239                if *b >= 0 {
240                    let mut result = Vec::new();
241                    for _ in 0..*b {
242                        result.extend(a.clone());
243                    }
244                    Ok(PythonValue::List(result))
245                }
246                else {
247                    Ok(PythonValue::List(Vec::new()))
248                }
249            }
250            (PythonValue::Tuple(a), PythonValue::Integer(b)) => {
251                if *b >= 0 {
252                    let mut result = Vec::new();
253                    for _ in 0..*b {
254                        result.extend(a.clone());
255                    }
256                    Ok(PythonValue::Tuple(result))
257                }
258                else {
259                    Ok(PythonValue::Tuple(Vec::new()))
260                }
261            }
262            _ => Err(PythonError::TypeError("unsupported operand type(s) for *".to_string())),
263        }
264    }
265
266    /// Divide two values
267    pub fn div(&self, other: &PythonValue) -> PythonResult<PythonValue> {
268        match (self, other) {
269            (_, PythonValue::Integer(0)) | (_, PythonValue::Float(0.0)) => {
270                Err(PythonError::ZeroDivisionError("division by zero".to_string()))
271            }
272            (PythonValue::Integer(a), PythonValue::Integer(b)) => Ok(PythonValue::Float((*a as f64) / (*b as f64))),
273            (PythonValue::Integer(a), PythonValue::Float(b)) => Ok(PythonValue::Float((*a as f64) / *b)),
274            (PythonValue::Float(a), PythonValue::Integer(b)) => Ok(PythonValue::Float(*a / (*b as f64))),
275            (PythonValue::Float(a), PythonValue::Float(b)) => Ok(PythonValue::Float(*a / *b)),
276            _ => Err(PythonError::TypeError("unsupported operand type(s) for /".to_string())),
277        }
278    }
279
280    /// Check equality
281    pub fn eq(&self, other: &PythonValue) -> bool {
282        self == other
283    }
284
285    /// Check less than
286    pub fn lt(&self, other: &PythonValue) -> PythonResult<bool> {
287        match (self, other) {
288            (PythonValue::Integer(a), PythonValue::Integer(b)) => Ok(a < b),
289            (PythonValue::Integer(a), PythonValue::Float(b)) => Ok((*a as f64) < *b),
290            (PythonValue::Float(a), PythonValue::Integer(b)) => Ok(*a < (*b as f64)),
291            (PythonValue::Float(a), PythonValue::Float(b)) => Ok(a < b),
292            (PythonValue::String(a), PythonValue::String(b)) => Ok(a < b),
293            _ => Err(PythonError::TypeError("unorderable types".to_string())),
294        }
295    }
296
297    /// Check greater than
298    pub fn gt(&self, other: &PythonValue) -> PythonResult<bool> {
299        match (self, other) {
300            (PythonValue::Integer(a), PythonValue::Integer(b)) => Ok(a > b),
301            (PythonValue::Integer(a), PythonValue::Float(b)) => Ok((*a as f64) > *b),
302            (PythonValue::Float(a), PythonValue::Integer(b)) => Ok(*a > (*b as f64)),
303            (PythonValue::Float(a), PythonValue::Float(b)) => Ok(a > b),
304            (PythonValue::String(a), PythonValue::String(b)) => Ok(a > b),
305            _ => Err(PythonError::TypeError("unorderable types".to_string())),
306        }
307    }
308}
309
310/// Python error type
311#[derive(Debug, Clone, PartialEq)]
312pub enum PythonError {
313    /// Method not found error
314    MethodNotFound(String),
315    /// Attribute not found error
316    AttributeNotFound(String),
317    /// Lexical analysis error
318    LexicalError(String),
319    /// Syntax analysis error
320    SyntaxError(String),
321    /// Runtime error
322    RuntimeError(String),
323    /// Type error
324    TypeError(String),
325    /// Argument error
326    ArgumentError(String),
327    /// Name error
328    NameError(String),
329    /// Index error
330    IndexError(String),
331    /// Key error
332    KeyError(String),
333    /// Zero division error
334    ZeroDivisionError(String),
335    /// IO error
336    IOError(String),
337    /// Import error
338    ImportError(String),
339}
340
341impl std::fmt::Display for PythonError {
342    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
343        match self {
344            PythonError::MethodNotFound(name) => write!(f, "Method not found: {}", name),
345            PythonError::AttributeNotFound(name) => write!(f, "Attribute not found: {}", name),
346            PythonError::LexicalError(msg) => write!(f, "Lexical error: {}", msg),
347            PythonError::SyntaxError(msg) => write!(f, "Syntax error: {}", msg),
348            PythonError::RuntimeError(msg) => write!(f, "Runtime error: {}", msg),
349            PythonError::TypeError(msg) => write!(f, "Type error: {}", msg),
350            PythonError::ArgumentError(msg) => write!(f, "Argument error: {}", msg),
351            PythonError::NameError(msg) => write!(f, "Name error: {}", msg),
352            PythonError::IndexError(msg) => write!(f, "Index error: {}", msg),
353            PythonError::KeyError(msg) => write!(f, "Key error: {}", msg),
354            PythonError::ZeroDivisionError(msg) => write!(f, "ZeroDivisionError: {}", msg),
355            PythonError::IOError(msg) => write!(f, "IO error: {}", msg),
356            PythonError::ImportError(msg) => write!(f, "Import error: {}", msg),
357        }
358    }
359}
360
361impl std::error::Error for PythonError {}
362
363/// Python result type
364pub type PythonResult<T> = std::result::Result<T, PythonError>;