Skip to main content

wolfram_expr/
conversion.rs

1use std::convert::TryFrom;
2
3use super::*;
4
5// Each `TryFrom<&'e Expr>` impl below fails with the original `&'e Expr`
6// back (mirroring `TryFrom<Vec<T>> for [T; N]` in std) so callers can
7// report or inspect what they actually got, without a bespoke error type.
8
9impl<'e> TryFrom<&'e Expr> for bool {
10    type Error = &'e Expr;
11
12    /// If this is the `True` or `False` symbol, return that.
13    ///
14    /// ```
15    /// # use wolfram_expr::{Expr, expr};
16    /// # use std::convert::TryFrom;
17    /// let is_true = bool::try_from(&expr!(System::True)).unwrap();
18    /// assert_eq!(is_true, true);
19    /// ```
20    fn try_from(expr: &'e Expr) -> Result<bool, &'e Expr> {
21        match expr.kind() {
22            ExprKind::Symbol(symbol) => match symbol.as_str() {
23                "System`True" => Ok(true),
24                "System`False" => Ok(false),
25                _ => Err(expr),
26            },
27            _ => Err(expr),
28        }
29    }
30}
31
32impl<'e> TryFrom<&'e Expr> for &'e str {
33    type Error = &'e Expr;
34
35    /// If this is an [`ExprKind::String`] expression, return that.
36    ///
37    /// ```
38    /// # use wolfram_expr::{Expr, expr};
39    /// # use std::convert::TryFrom;
40    /// let expr = expr!("hello");
41    /// let s = <&str>::try_from(&expr).unwrap();
42    /// assert_eq!(s, "hello");
43    /// ```
44    fn try_from(expr: &'e Expr) -> Result<&'e str, &'e Expr> {
45        match expr.kind() {
46            ExprKind::String(string) => Ok(string.as_str()),
47            _ => Err(expr),
48        }
49    }
50}
51
52impl<'e> TryFrom<&'e Expr> for &'e Symbol {
53    type Error = &'e Expr;
54
55    /// If this is a [`Symbol`] expression, return that.
56    ///
57    /// ```
58    /// # use wolfram_expr::{Expr, Symbol, expr};
59    /// # use std::convert::TryFrom;
60    /// let expr = expr!(System::Pi);
61    /// let sym = <&Symbol>::try_from(&expr).unwrap();
62    /// assert_eq!(sym.as_str(), "System`Pi");
63    /// ```
64    fn try_from(expr: &'e Expr) -> Result<&'e Symbol, &'e Expr> {
65        match expr.kind() {
66            ExprKind::Symbol(symbol) => Ok(symbol),
67            _ => Err(expr),
68        }
69    }
70}
71
72impl<'e> TryFrom<&'e Expr> for &'e Normal {
73    type Error = &'e Expr;
74
75    /// If this is a [`Normal`] expression, return that.
76    ///
77    /// ```
78    /// # use wolfram_expr::{Expr, Normal, expr};
79    /// # use std::convert::TryFrom;
80    /// let expr = expr!(System::List[1, 2, 3]);
81    /// let normal = <&Normal>::try_from(&expr).unwrap();
82    /// assert_eq!(normal.elements().len(), 3);
83    /// ```
84    fn try_from(expr: &'e Expr) -> Result<&'e Normal, &'e Expr> {
85        match expr.kind() {
86            ExprKind::Normal(normal) => Ok(normal),
87            _ => Err(expr),
88        }
89    }
90}
91
92impl<'e> TryFrom<&'e Expr> for i64 {
93    type Error = &'e Expr;
94
95    /// If this is an [`ExprKind::Integer`] expression, return that.
96    ///
97    /// ```
98    /// # use wolfram_expr::{Expr, expr};
99    /// # use std::convert::TryFrom;
100    /// let i = i64::try_from(&expr!(42)).unwrap();
101    /// assert_eq!(i, 42);
102    /// ```
103    fn try_from(expr: &'e Expr) -> Result<i64, &'e Expr> {
104        match expr.kind() {
105            ExprKind::Integer(int) => Ok(*int),
106            _ => Err(expr),
107        }
108    }
109}
110
111impl<'e> TryFrom<&'e Expr> for f64 {
112    type Error = &'e Expr;
113
114    /// If this is an [`ExprKind::Real`] expression, return that.
115    ///
116    /// ```
117    /// # use wolfram_expr::{Expr, expr};
118    /// # use std::convert::TryFrom;
119    /// let r = f64::try_from(&expr!(4.2)).unwrap();
120    /// assert_eq!(r, 4.2);
121    /// ```
122    fn try_from(expr: &'e Expr) -> Result<f64, &'e Expr> {
123        match expr.kind() {
124            ExprKind::Real(real) => Ok(real.into_inner()),
125            _ => Err(expr),
126        }
127    }
128}
129
130impl Expr {
131    // These accessors are deprecated: use the `TryFrom<&Expr>` impls above
132    // instead — same behavior, drop-in replacement. None of them are used
133    // inside this crate.
134
135    /// If this is a [`Normal`] expression, return that. Otherwise return None.
136    ///
137    /// # Migration
138    ///
139    /// ```
140    /// # use wolfram_expr::{Expr, Normal, expr};
141    /// # use std::convert::TryFrom;
142    /// # let expr = expr!(System::List[1, 2, 3]);
143    /// let normal: Option<&Normal> = <&Normal>::try_from(&expr).ok();
144    /// ```
145    #[deprecated(note = "use `<&Normal>::try_from(expr)` instead")]
146    pub fn try_as_normal(&self) -> Option<&Normal> {
147        <&Normal>::try_from(self).ok()
148    }
149
150    /// If this is the `True` or `False` symbol, return that. Otherwise None.
151    ///
152    /// # Migration
153    ///
154    /// ```
155    /// # use wolfram_expr::{Expr, expr};
156    /// # use std::convert::TryFrom;
157    /// # let expr = expr!(System::True);
158    /// let is_true_or_false: Option<bool> = bool::try_from(&expr).ok();
159    /// ```
160    #[deprecated(note = "use `bool::try_from(expr)` instead")]
161    pub fn try_as_bool(&self) -> Option<bool> {
162        bool::try_from(self).ok()
163    }
164
165    /// If this is an [`ExprKind::String`] expression, return that. Otherwise return None.
166    ///
167    /// # Migration
168    ///
169    /// ```
170    /// # use wolfram_expr::{Expr, expr};
171    /// # use std::convert::TryFrom;
172    /// # let expr = expr!("hello");
173    /// let s: Option<&str> = <&str>::try_from(&expr).ok();
174    /// ```
175    #[deprecated(note = "use `<&str>::try_from(expr)` instead")]
176    pub fn try_as_str(&self) -> Option<&str> {
177        <&str>::try_from(self).ok()
178    }
179
180    /// If this is a [`Symbol`] expression, return that. Otherwise return None.
181    ///
182    /// # Migration
183    ///
184    /// ```
185    /// # use wolfram_expr::{Expr, Symbol, expr};
186    /// # use std::convert::TryFrom;
187    /// # let expr = expr!(System::Pi);
188    /// let sym: Option<&Symbol> = <&Symbol>::try_from(&expr).ok();
189    /// ```
190    #[deprecated(note = "use `<&Symbol>::try_from(expr)` instead")]
191    pub fn try_as_symbol(&self) -> Option<&Symbol> {
192        <&Symbol>::try_from(self).ok()
193    }
194
195    /// If this is a [`Number`] expression, return that. Otherwise return None.
196    ///
197    /// # Migration
198    ///
199    /// ```
200    /// # use wolfram_expr::{Expr, expr};
201    /// # use std::convert::TryFrom;
202    /// # let expr = expr!(42);
203    /// let int: Option<i64> = i64::try_from(&expr).ok();
204    /// let real: Option<f64> = f64::try_from(&expr).ok();
205    /// ```
206    #[deprecated(note = "use `i64::try_from(expr)` / `f64::try_from(expr)` instead")]
207    #[allow(deprecated)]
208    pub fn try_as_number(&self) -> Option<Number> {
209        match self.kind() {
210            ExprKind::Integer(int) => Some(Number::Integer(*int)),
211            ExprKind::Real(real) => Some(Number::Real(*real)),
212            _ => None,
213        }
214    }
215
216    //---------------------------------------------------------------------------
217    // SEMVER: These methods have been replaced; remove them in a future version.
218    //---------------------------------------------------------------------------
219
220    #[deprecated(note = "use `<&Normal>::try_from(expr)` instead")]
221    #[allow(missing_docs, deprecated)]
222    pub fn try_normal(&self) -> Option<&Normal> {
223        self.try_as_normal()
224    }
225
226    #[deprecated(note = "use `<&Symbol>::try_from(expr)` instead")]
227    #[allow(missing_docs, deprecated)]
228    pub fn try_symbol(&self) -> Option<&Symbol> {
229        self.try_as_symbol()
230    }
231
232    #[deprecated(note = "use `i64::try_from(expr)` / `f64::try_from(expr)` instead")]
233    #[allow(missing_docs, deprecated)]
234    pub fn try_number(&self) -> Option<Number> {
235        self.try_as_number()
236    }
237}
238
239//=======================================
240// Conversion trait impl's
241//=======================================
242
243impl From<Symbol> for Expr {
244    fn from(sym: Symbol) -> Expr {
245        Expr::symbol(sym)
246    }
247}
248
249impl From<&Symbol> for Expr {
250    fn from(sym: &Symbol) -> Expr {
251        Expr::symbol(sym)
252    }
253}
254
255impl From<Normal> for Expr {
256    fn from(normal: Normal) -> Expr {
257        Expr {
258            inner: Arc::new(ExprKind::Normal(normal)),
259        }
260    }
261}
262
263impl From<bool> for Expr {
264    fn from(value: bool) -> Expr {
265        match value {
266            true => crate::expr!(System::True),
267            false => crate::expr!(System::False),
268        }
269    }
270}
271
272macro_rules! string_like {
273    ($($t:ty),*) => {
274        $(
275            impl From<$t> for Expr {
276                fn from(s: $t) -> Expr {
277                    Expr::string(s)
278                }
279            }
280        )*
281    }
282}
283
284string_like!(&str, &String, String);
285
286//--------------------
287// Integer conversions
288//--------------------
289
290impl From<u8> for Expr {
291    fn from(int: u8) -> Expr {
292        Expr::from(i64::from(int))
293    }
294}
295
296impl From<i8> for Expr {
297    fn from(int: i8) -> Expr {
298        Expr::from(i64::from(int))
299    }
300}
301
302impl From<u16> for Expr {
303    fn from(int: u16) -> Expr {
304        Expr::from(i64::from(int))
305    }
306}
307
308impl From<i16> for Expr {
309    fn from(int: i16) -> Expr {
310        Expr::from(i64::from(int))
311    }
312}
313
314impl From<u32> for Expr {
315    fn from(int: u32) -> Expr {
316        Expr::from(i64::from(int))
317    }
318}
319
320impl From<i32> for Expr {
321    fn from(int: i32) -> Expr {
322        Expr::from(i64::from(int))
323    }
324}
325
326impl From<i64> for Expr {
327    fn from(int: i64) -> Expr {
328        Expr::new(ExprKind::Integer(int))
329    }
330}
331
332impl From<f64> for Expr {
333    fn from(f: f64) -> Expr {
334        Expr::real(f)
335    }
336}
337
338// impl From<Normal> for ExprKind {
339//     fn from(normal: Normal) -> ExprKind {
340//         ExprKind::Normal(Box::new(normal))
341//     }
342// }
343
344// impl From<Symbol> for ExprKind {
345//     fn from(symbol: Symbol) -> ExprKind {
346//         ExprKind::Symbol(symbol)
347//     }
348// }
349
350#[allow(deprecated)]
351impl From<Number> for ExprKind {
352    fn from(number: Number) -> ExprKind {
353        match number {
354            Number::Integer(int) => ExprKind::Integer(int),
355            Number::Real(real) => ExprKind::Real(real),
356        }
357    }
358}
359
360//==============================
361// New WXF-derived From<T> impls
362//==============================
363
364impl From<ByteArray> for Expr {
365    fn from(b: ByteArray) -> Expr {
366        Expr {
367            inner: Arc::new(ExprKind::ByteArray(b)),
368        }
369    }
370}
371
372impl From<Association> for Expr {
373    fn from(a: Association) -> Expr {
374        Expr {
375            inner: Arc::new(ExprKind::Association(a)),
376        }
377    }
378}
379
380impl From<Vec<Expr>> for Expr {
381    fn from(v: Vec<Expr>) -> Expr {
382        Expr::list(v)
383    }
384}
385
386impl From<NumericArray> for Expr {
387    fn from(a: NumericArray) -> Expr {
388        Expr {
389            inner: Arc::new(ExprKind::NumericArray(a)),
390        }
391    }
392}
393
394impl From<PackedArray> for Expr {
395    fn from(a: PackedArray) -> Expr {
396        Expr {
397            inner: Arc::new(ExprKind::PackedArray(a)),
398        }
399    }
400}
401impl From<BigInteger> for Expr {
402    fn from(n: BigInteger) -> Expr {
403        Expr {
404            inner: Arc::new(ExprKind::BigInteger(n)),
405        }
406    }
407}
408impl From<BigReal> for Expr {
409    fn from(r: BigReal) -> Expr {
410        Expr {
411            inner: Arc::new(ExprKind::BigReal(r)),
412        }
413    }
414}