molt_forked/
value.rs

1//! The Value Type
2//!
3//! The [`Value`] struct is the standard representation of a data value
4//! in the Molt language.  It represents a single immutable data value; the
5//! data is reference-counted, so instances can be cloned efficiently.  Its
6//! content may be any TCL data value: e.g., a number, a list, a string, or a value of
7//! an arbitrary type that meets certain requirements.
8//!
9//! In TCL, "everything is a string": every value is defined by its _string
10//! representation_, or _string rep_.  For example, "one two three" is the string rep of a
11//! list with three items, the strings "one", "two", and "three".  A string that is a
12//! valid string rep for multiple types can be interpreted as any of those types;
13//! for example, the string "5" can be used as a string, the integer 5, or a list of one
14//! element, the value "5".
15//!
16//! Internally, the `Value` can also have a `data representation`, or `data rep`, that
17//! reflects how the value has been most recently used.  Once a `Value` has been used
18//! as a list, it will continue to be efficiently used as a list (until it is used something
19//! with a different data rep).
20//!
21//! # Value is not Sync!
22//!
23//! A `Value` is associated with a particular `Interp` and changes internally to optimize
24//! performance within that `Interp`.  Consequently, `Values` are not `Sync`.  `Values`
25//! may be used to pass values between `Interps` in the same thread (at the cost of
26//! potential shimmering), but between threads one should pass the value's string rep instead.
27//!
28//! # Comparisons
29//!
30//! If two `Value`'s are compared for equality in Rust, Rust compares their string reps;
31//! the client may also use the two `Values` as some other type before comparing them.  In
32//! TCL expressions the `==` and `!=` operators compare numbers and the
33//! `eq` and `ne` operators compare string reps.
34//!
35//! # Internal Representation
36//!
37//! "Everything is a string"; thus, every `Value` has a string
38//! representation, or _string rep_.  But for efficiency with numbers, lists,
39//! and user-defined binary data structures, the `Value` also caches a
40//! data representation, or _data rep_.
41//!
42//! A `Value` can have just a string rep, just a data rep, or both.
43//! Like the `Tcl_Obj` in standard TCL, the `Value` is like a two-legged stork: it
44//! can stand one leg, the other leg, or both legs.
45//!
46//! A client can ask the `Value` for its string, which is always available
47//! and will be computed from the data rep if it doesn't already exist.  (Once
48//! computed, the string rep never changes.)  A client can also ask
49//! the `Value` for any other type it desires.  If the requested data rep
50//! is already available, it will be returned; otherwise, the `Value` will
51//! attempt to parse it from the string_rep, returning an error result on failure.  The
52//! most recent data rep is cached for later.
53//!
54//! For example, consider the following sequence:
55//!
56//! * A computation yields a `Value` containing the integer 5. The data rep is
57//!   a `MoltInt`, and the string rep is undefined.
58//!
59//! * The client asks for the string, and the string rep "5" is computed.
60//!
61//! * The client asks for the value's integer value.  It is available and is returned.
62//!
63//! * The client asks for the value's value as a MoltList.  This is possible, because
64//!   the string "5" can be interpreted as a list of one element, the
65//!   string "5".  A new data rep is computed and saved, replacing the previous one.
66//!
67//! With this scheme, long series of computations can be carried
68//! out efficiently using only the the data rep, incurring the parsing cost at most
69//! once, while preserving TCL's "everything is a string" semantics.
70//!
71//! **Shimmering**: Converting from one data rep to another is expensive, as it involves parsing
72//! the string value.  Performance can suffer if the user's code switches rapidly from one data
73//! rep to another, e.g., in a tight loop.  The effect, which is known as "shimmering",
74//! can usually be avoided with a little care.  Note that accessing the value's string rep
75//! doesn't cause shimmering; the string is always readily available.
76//!
77//! `Value` handles strings, integers, floating-point values, lists, and a few other things as
78//! special cases, since they are part of the language and are so frequently used.
79//! In addition, a `Value` can also contain _external types_: Rust types that implement
80//! certain traits.
81//!
82//! # External Types
83//!
84//! Any type that implements the `std::fmt::Display`, `std::fmt::Debug`,
85//! and `std::str::FromStr` traits can be saved in a `Value`.  The struct's
86//! `Display` and `FromStr` trait implementations are used to convert between
87//! the string rep and data rep.
88//!
89//! * The `Display` implementation is responsible for producing the value's string rep.
90//!
91//! * The `FromStr` implementation is responsible for producing the value's data rep from
92//!   a string, and so must be able to parse the `Display` implementation's
93//!   output.
94//!
95//! * The string rep should be chosen so as to fit in well with TCL syntax, lest
96//!   confusion, quoting hell, and comedy should ensue.  (You'll know it when you
97//!   see it.)
98//!
99//! ## Example
100//!
101//! For example, the following code shows how to define an external type implementing
102//! a simple enum.
103//!
104//! ```
105//! use molt::types::*;
106//! use std::fmt;
107//! use std::str::FromStr;
108//!
109//! #[derive(Debug, PartialEq, Copy, Clone)]
110//! pub enum Flavor {
111//!     SALTY,
112//!     SWEET,
113//! }
114//!
115//! impl fmt::Display for Flavor {
116//!     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117//!         if *self == Flavor::SALTY {
118//!             write!(f, "salty")
119//!         } else {
120//!             write!(f, "sweet")
121//!         }
122//!     }
123//! }
124//!
125//! impl FromStr for Flavor {
126//!     type Err = String;
127//!
128//!     fn from_str(value: &str) -> Result<Self, Self::Err> {
129//!         let value = value.to_lowercase();
130//!
131//!         if value == "salty" {
132//!             Ok(Flavor::SALTY)
133//!         } else if value == "sweet" {
134//!             Ok(Flavor::SWEET)
135//!         } else {
136//!            // The error message doesn't matter to Molt
137//!            Err("Not a flavor string".to_string())
138//!         }
139//!     }
140//! }
141//!
142//! impl Flavor {
143//!     /// A convenience: retrieves the enumerated value, converting it from
144//!     /// `Option<Flavor>` into `Result<Flavor,Exception>`.
145//!     pub fn from_molt(value: &Value) -> Result<Self, Exception> {
146//!         if let Some(x) = value.as_copy::<Flavor>() {
147//!             Ok(x)
148//!         } else {
149//!             Err(Exception::molt_err(Value::from("Not a flavor string")))
150//!         }
151//!     }
152//! }
153//! ```
154//!
155//! # Special Implementation Types
156//!
157//! Values can also be interpreted as two special types, `Script` and `VarName`.  The
158//! Interpreter uses the (non-public) `as_script` method to parse script bodies for
159//! evaluation; generally this means that a script will get parsed only once.
160//!
161//! Similarly, `as_var_name` interprets a variable name reference as a `VarName`, which
162//! contains the variable name and, optionally, an array index.  This is usually hidden
163//! from the extension author by the `var` and `set_var` methods, but it is available if
164//! publically if needed.
165//!
166//! [`Value`]: struct.Value.html
167
168use crate::{
169    dict::{dict_to_string, list_to_dict},
170    expr::Datum,
171    list::{get_list, list_to_string},
172    parser::{self, Script},
173    types::{Exception, MoltDict, MoltFloat, MoltInt, MoltList, VarName},
174};
175use std::{
176    any::{Any, TypeId},
177    cell::{RefCell, UnsafeCell},
178    fmt::{Debug, Display},
179    hash::{Hash, Hasher},
180    rc::Rc,
181    str::FromStr,
182};
183
184//-----------------------------------------------------------------------------
185// Public Data Types
186
187/// The `Value` type. See [the module level documentation](index.html) for more.
188#[derive(Clone)]
189pub struct Value {
190    /// The actual data, to be shared among multiple instances of `Value`.
191    inner: Rc<InnerValue>,
192}
193
194impl Hash for Value {
195    // A Value is hashed according to its string rep; all Values with the same string rep
196    // are identical.
197    fn hash<H: Hasher>(&self, state: &mut H) {
198        self.as_str().hash(state);
199    }
200}
201
202/// The inner value of a `Value`, to be wrapped in an `Rc<T>` so that `Values` can be shared.
203#[derive(Debug)]
204struct InnerValue {
205    string_rep: UnsafeCell<Option<String>>,
206    data_rep: RefCell<DataRep>,
207}
208
209impl std::fmt::Debug for Value {
210    /// The Debug formatter for values.
211    ///
212    /// TODO: This should indicate something about the data rep as well, especially for
213    /// values in which the string rep isn't yet set.
214    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215        write!(f, "Value[{}]", self.as_str())
216    }
217}
218
219impl Value {
220    /// Creates a value whose `InnerValue` is defined by its string rep.
221    fn inner_from_string(str: String) -> Self {
222        let inner = InnerValue {
223            string_rep: UnsafeCell::new(Some(str)),
224            data_rep: RefCell::new(DataRep::None),
225        };
226
227        Self { inner: Rc::new(inner) }
228    }
229
230    /// Creates a value whose `InnerValue` is defined by its data rep.
231    fn inner_from_data(data: DataRep) -> Self {
232        let inner = InnerValue {
233            string_rep: UnsafeCell::new(None),
234            data_rep: RefCell::new(data),
235        };
236
237        Self { inner: Rc::new(inner) }
238    }
239}
240
241impl Display for Value {
242    /// The `Display` formatter for `Value`.  Outputs the value's string rep.
243    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
244        write!(f, "{}", self.as_str())
245    }
246}
247
248impl Eq for Value {}
249impl PartialEq for Value {
250    /// Two Values are equal if their string representations are equal.  Application code will
251    /// often want to compare values numerically.
252    fn eq(&self, other: &Self) -> bool {
253        self.as_str() == other.as_str()
254    }
255}
256
257impl From<String> for Value {
258    /// Creates a new `Value` from the given String.
259    ///
260    /// # Example
261    ///
262    /// ```
263    /// use molt::types::Value;
264    /// let string = String::from("My New String");
265    /// let value = Value::from(string);
266    /// assert_eq!(value.as_str(), "My New String");
267    /// ```
268    fn from(str: String) -> Self {
269        Value::inner_from_string(str)
270    }
271}
272
273impl From<&str> for Value {
274    /// Creates a new `Value` from the given string slice.
275    ///
276    /// # Example
277    ///
278    /// ```
279    /// use molt::types::Value;
280    /// let value = Value::from("My String Slice");
281    /// assert_eq!(value.as_str(), "My String Slice");
282    /// ```
283    fn from(str: &str) -> Self {
284        Value::inner_from_string(str.to_string())
285    }
286}
287
288impl From<&String> for Value {
289    /// Creates a new `Value` from the given string reference.
290    ///
291    /// # Example
292    ///
293    /// ```
294    /// use molt::types::Value;
295    /// let value = Value::from("My String Slice");
296    /// assert_eq!(value.as_str(), "My String Slice");
297    /// ```
298    fn from(str: &String) -> Self {
299        Value::inner_from_string(str.to_string())
300    }
301}
302
303impl From<bool> for Value {
304    /// Creates a new `Value` whose data representation is a `bool`.  The value's
305    /// string representation will be "1" or "0".
306    ///
307    /// # Example
308    ///
309    /// ```
310    /// use molt::types::Value;
311    /// let value = Value::from(true);
312    /// assert_eq!(value.as_str(), "1");
313    ///
314    /// let value = Value::from(false);
315    /// assert_eq!(value.as_str(), "0");
316    /// ```
317    fn from(flag: bool) -> Self {
318        Value::inner_from_data(DataRep::Bool(flag))
319    }
320}
321
322impl From<MoltDict> for Value {
323    /// Creates a new `Value` whose data representation is a `MoltDict`.
324    ///
325    /// # Example
326    ///
327    /// ```
328    /// use molt::types::Value;
329    /// use molt::types::MoltDict;
330    /// use molt::dict::dict_new;
331    ///
332    /// let mut dict: MoltDict = dict_new();
333    /// dict.insert(Value::from("abc"), Value::from("123"));
334    /// let value = Value::from(dict);
335    /// assert_eq!(value.as_str(), "abc 123");
336    /// ```
337    fn from(dict: MoltDict) -> Self {
338        Value::inner_from_data(DataRep::Dict(Rc::new(dict)))
339    }
340}
341
342impl From<MoltInt> for Value {
343    /// Creates a new `Value` whose data representation is a `MoltInt`.
344    ///
345    /// # Example
346    ///
347    /// ```
348    /// use molt::types::Value;
349    ///
350    /// let value = Value::from(123);
351    /// assert_eq!(value.as_str(), "123");
352    /// ```
353    fn from(int: MoltInt) -> Self {
354        Value::inner_from_data(DataRep::Int(int))
355    }
356}
357
358impl From<MoltFloat> for Value {
359    /// Creates a new `Value` whose data representation is a `MoltFloat`.
360    ///
361    /// # String Representation
362    ///
363    /// The string representation of the value will be however Rust's `format!` macro
364    /// formats floating point numbers by default.  **Note**: this isn't quite what we
365    /// want; Standard TCL goes to great lengths to ensure that the formatted string
366    /// will yield exactly the same floating point number when it is parsed.  Rust
367    /// will format the number `5.0` as `5`, turning it into a integer if parsed naively. So
368    /// there is more work to be done here.
369    ///
370    /// # Example
371    ///
372    /// ```
373    /// use molt::types::Value;
374    ///
375    /// let value = Value::from(12.34);
376    /// assert_eq!(value.as_str(), "12.34");
377    /// ```
378    fn from(flt: MoltFloat) -> Self {
379        Value::inner_from_data(DataRep::Flt(flt))
380    }
381}
382
383impl From<MoltList> for Value {
384    /// Creates a new `Value` whose data representation is a `MoltList`.
385    ///
386    /// # Example
387    ///
388    /// ```
389    /// use molt::types::Value;
390    ///
391    /// let list = vec![Value::from(1234), Value::from("abc")];
392    /// let value = Value::from(list);
393    /// assert_eq!(value.as_str(), "1234 abc");
394    /// ```
395    fn from(list: MoltList) -> Self {
396        Value::inner_from_data(DataRep::List(Rc::new(list)))
397    }
398}
399
400impl From<&[Value]> for Value {
401    /// Creates a new `Value` whose data representation is a `MoltList`.
402    ///
403    /// # Example
404    ///
405    /// ```
406    /// use molt::types::Value;
407    ///
408    /// let values = [Value::from(1234), Value::from("abc")];
409    /// let value = Value::from(&values[..]);
410    /// assert_eq!(value.as_str(), "1234 abc");
411    /// ```
412    fn from(list: &[Value]) -> Self {
413        Value::inner_from_data(DataRep::List(Rc::new(list.to_vec())))
414    }
415}
416
417impl Value {
418    /// Returns the empty `Value`, a value whose string representation is the empty
419    /// string.
420    ///
421    /// TODO: This should really be a constant, but there's way to build it as one
422    /// unless I use lazy_static.
423    pub fn empty() -> Value {
424        Value::inner_from_string("".into())
425    }
426
427    /// Returns the value's string representation as a reference-counted
428    /// string.
429    ///
430    /// **Note**: This is the standard way of retrieving a `Value`'s
431    /// string rep, as unlike `to_string` it doesn't create a new `String`.
432    ///
433    /// # Example
434    ///
435    /// ```
436    /// use molt::types::Value;
437    /// let value = Value::from(123);
438    /// assert_eq!(value.as_str(), "123");
439    /// ```
440    pub fn as_str(&self) -> &str {
441        // FIRST, get the string rep, computing it from the data_rep if necessary.
442        // self.inner.string_rep.get_or_init(|| (self.inner.data_rep.borrow()).to_string())
443
444        // NOTE: This method is the only place where the string_rep is queried.
445        let slot = unsafe { &*self.inner.string_rep.get() };
446
447        if let Some(inner) = slot {
448            return inner;
449        }
450
451        // NOTE: This is the only place where the string_rep is set.
452        // Because we returned it if it was Some, it is only ever set once.
453        // Thus, this is safe: as_str() is the only way to retrieve the string_rep,
454        // and it computes the string_rep lazily after which it is immutable.
455        let slot = unsafe { &mut *self.inner.string_rep.get() };
456        *slot = Some((self.inner.data_rep.borrow()).to_string());
457
458        slot.as_ref().expect("string rep")
459    }
460
461    /// Returns the value's string representation if it is already ready.
462    /// This is useful for implementing command line switches.
463    ///
464    /// # Example
465    ///
466    /// ```
467    /// use molt::types::Value;
468    /// let value = Value::from(123);
469    /// assert_eq!(value.try_as_str(), None);
470    /// assert_eq!(value.as_str(), "123");
471    /// assert_eq!(value.try_as_str(), Some("123"));
472    /// let value_str = Value::from("123");
473    /// assert_eq!(value_str.try_as_str(), Some("123"));
474    /// ```
475    pub fn try_as_str(&self) -> Option<&str> {
476        unsafe { &*self.inner.string_rep.get() }.as_ref().map(|x| x.as_ref())
477    }
478
479    /// Tries to return the `Value` as a `bool`, parsing the
480    /// value's string representation if necessary.
481    ///
482    /// # Boolean Strings
483    ///
484    /// The following are valid boolean strings, regardless of case: `true`,
485    /// `false`, `on`, `off`, `yes`, `no`, `1`, `0`.  Note that other numeric strings are
486    /// _not_ valid boolean strings.
487    ///
488    /// # Numeric Values
489    ///
490    /// Non-negative numbers are interpreted as true; zero is interpreted as false.
491    ///
492    /// # Example
493    ///
494    /// ```
495    /// use molt::types::Value;
496    /// use molt::types::Exception;
497    /// # fn dummy() -> Result<bool,Exception> {
498    /// // All of the following can be interpreted as booleans.
499    /// let value = Value::from(true);
500    /// let flag = value.as_bool()?;
501    /// assert_eq!(flag, true);
502    ///
503    /// let value = Value::from("no");
504    /// let flag = value.as_bool()?;
505    /// assert_eq!(flag, false);
506    ///
507    /// let value = Value::from(5);
508    /// let flag = value.as_bool()?;
509    /// assert_eq!(flag, true);
510    ///
511    /// let value = Value::from(0);
512    /// let flag = value.as_bool()?;
513    /// assert_eq!(flag, false);
514    ///
515    /// let value = Value::from(1.1);
516    /// let flag = value.as_bool()?;
517    /// assert_eq!(flag, true);
518    ///
519    /// let value = Value::from(0.0);
520    /// let flag = value.as_bool()?;
521    /// assert_eq!(flag, false);
522    ///
523    /// // Numeric strings can not, unless evaluated as expressions.
524    /// let value = Value::from("123");
525    /// assert!(value.as_bool().is_err());
526    /// # Ok(true)
527    /// # }
528    /// ```
529    pub fn as_bool(&self) -> Result<bool, Exception> {
530        // Extra block, so that the dref is dropped before we borrow mutably.
531        {
532            let data_ref = self.inner.data_rep.borrow();
533
534            // FIRST, if we have a boolean then just return it.
535            if let DataRep::Bool(flag) = *data_ref {
536                return Ok(flag);
537            }
538
539            // NEXT, if we have a number return whether it's zero or not.
540            if let DataRep::Int(int) = *data_ref {
541                return Ok(int != 0);
542            }
543
544            if let DataRep::Flt(flt) = *data_ref {
545                return Ok(flt != 0.0);
546            }
547        }
548
549        // NEXT, Try to parse the string_rep as a boolean
550        let str = self.as_str();
551        let flag = Value::get_bool(str)?;
552        *(self.inner.data_rep.borrow_mut()) = DataRep::Bool(flag);
553        Ok(flag)
554    }
555
556    /// Converts a string argument into a boolean, returning an error on failure.
557    ///
558    /// Molt accepts the following strings as Boolean values:
559    ///
560    /// * **true**: `true`, `yes`, `on`, `1`
561    /// * **false**: `false`, `no`, `off`, `0`
562    ///
563    /// Parsing is case-insensitive, and leading and trailing whitespace are ignored.
564    ///
565    /// This method does not evaluate expressions; use `molt::expr` to evaluate boolean
566    /// expressions.
567    ///
568    /// # Example
569    ///
570    /// ```
571    /// # use molt::types::*;
572    /// # fn dummy() -> Result<bool,Exception> {
573    /// let arg = "yes";
574    /// let flag = Value::get_bool(arg)?;
575    /// assert!(flag);
576    /// # Ok(flag)
577    /// # }
578    /// ```
579    pub fn get_bool(arg: &str) -> Result<bool, Exception> {
580        let orig = arg;
581        let value: &str = &arg.trim().to_lowercase();
582        match value {
583            "1" | "true" | "yes" | "on" => Ok(true),
584            "0" | "false" | "no" | "off" => Ok(false),
585            _ => molt_err!("expected boolean but got \"{}\"", orig),
586        }
587    }
588
589    /// Tries to return the `Value` as an `Rc<MoltDict>`, parsing the
590    /// value's string representation if necessary.
591    ///
592    /// # Example
593    ///
594    /// ```
595    /// use std::rc::Rc;
596    /// use molt::types::Value;
597    /// use molt::types::MoltDict;
598    /// use molt::types::Exception;
599    /// # fn dummy() -> Result<(),Exception> {
600    ///
601    /// let value = Value::from("abc 1234");
602    /// let dict: Rc<MoltDict> = value.as_dict()?;
603    ///
604    /// assert_eq!(dict.len(), 1);
605    /// assert_eq!(dict.get(&Value::from("abc")), Some(&Value::from("1234")));
606    ///
607    /// # Ok(())
608    /// # }
609    /// ```
610    pub fn as_dict(&self) -> Result<Rc<MoltDict>, Exception> {
611        // FIRST, if we have the desired type, return it.
612        if let DataRep::Dict(dict) = &*self.inner.data_rep.borrow() {
613            return Ok(dict.clone());
614        }
615
616        // NEXT, try to parse the string_rep as a list; then turn it into a dict.
617        let str = self.as_str();
618        let list = get_list(str)?;
619
620        if list.len() % 2 != 0 {
621            return molt_err!("missing value to go with key");
622        }
623
624        let dict = Rc::new(list_to_dict(&list));
625
626        *self.inner.data_rep.borrow_mut() = DataRep::Dict(dict.clone());
627
628        Ok(dict)
629    }
630
631    /// Tries to return the `Value` as a `MoltDict`, parsing the
632    /// value's string representation if necessary.
633    ///
634    /// Use [`as_dict`](#method.as_dict) when simply referring to the dict's content;
635    /// use this method when constructing a new dict from the old one.
636    ///
637    /// # Example
638    ///
639    /// ```
640    /// use molt::types::Value;
641    /// use molt::types::MoltDict;
642    /// use molt::types::Exception;
643    /// # fn dummy() -> Result<String,Exception> {
644    ///
645    /// let value = Value::from("abc 1234");
646    /// let dict: MoltDict = value.to_dict()?;
647    /// assert_eq!(dict.len(), 2);
648    /// assert_eq!(dict.get(&Value::from("abc")), Some(&Value::from("1234")));
649    ///
650    /// # Ok("dummy".to_string())
651    /// # }
652    /// ```
653    pub fn to_dict(&self) -> Result<MoltDict, Exception> {
654        Ok((&*self.as_dict()?).to_owned())
655    }
656
657    /// Tries to return the `Value` as a `MoltInt`, parsing the
658    /// value's string representation if necessary.
659    ///
660    /// # Integer Syntax
661    ///
662    /// Molt accepts decimal integer strings, and hexadecimal integer strings
663    /// with a `0x` prefix.  Strings may begin with a unary "+" or "-".  Hex
664    /// digits may be in upper or lower case.
665    ///
666    /// # Example
667    ///
668    /// ```
669    /// use molt::types::Value;
670    /// use molt::types::MoltInt;
671    /// use molt::types::Exception;
672    /// # fn dummy() -> Result<MoltInt,Exception> {
673    ///
674    /// let value = Value::from(123);
675    /// let int = value.as_int()?;
676    /// assert_eq!(int, 123);
677    ///
678    /// let value = Value::from("OxFF");
679    /// let int = value.as_int()?;
680    /// assert_eq!(int, 255);
681    /// # Ok(1)
682    /// # }
683    /// ```
684    pub fn as_int(&self) -> Result<MoltInt, Exception> {
685        // FIRST, if we have an integer then just return it.
686        if let DataRep::Int(int) = *self.inner.data_rep.borrow() {
687            return Ok(int);
688        }
689
690        // NEXT, Try to parse the string_rep as an integer
691        let str = self.as_str();
692        let int = Value::get_int(str)?;
693        *self.inner.data_rep.borrow_mut() = DataRep::Int(int);
694        Ok(int)
695    }
696
697    /// Converts a string argument into a `MoltInt`, returning an error on failure.
698    ///
699    /// Molt accepts decimal integer strings, and hexadecimal integer strings
700    /// with a `0x` prefix.  Strings may begin with a unary "+" or "-".  Leading and
701    /// trailing whitespace is ignored.
702    ///
703    /// # Example
704    ///
705    /// ```
706    /// # use molt::types::*;
707    /// # fn dummy() -> Result<MoltInt,Exception> {
708    /// let arg = "1";
709    /// let int = Value::get_int(arg)?;
710    /// # Ok(int)
711    /// # }
712    /// ```
713    pub fn get_int(arg: &str) -> Result<MoltInt, Exception> {
714        let orig = arg;
715        let mut arg = arg.trim();
716        let mut minus = 1;
717
718        if arg.starts_with('+') {
719            arg = &arg[1..];
720        } else if arg.starts_with('-') {
721            minus = -1;
722            arg = &arg[1..];
723        }
724
725        let parse_result = if arg.starts_with("0x") {
726            MoltInt::from_str_radix(&arg[2..], 16)
727        } else {
728            arg.parse::<MoltInt>()
729        };
730
731        match parse_result {
732            Ok(int) => Ok(minus * int),
733            Err(_) => molt_err!("expected integer but got \"{}\"", orig),
734        }
735    }
736
737    /// Tries to return the `Value` as a `MoltFloat`, parsing the
738    /// value's string representation if necessary.
739    ///
740    /// # Floating-Point Syntax
741    ///
742    /// Molt accepts the same floating-point strings as Rust's standard numeric parser.
743    ///
744    /// # Example
745    ///
746    /// ```
747    /// use molt::types::Value;
748    /// use molt::types::MoltFloat;
749    /// use molt::types::Exception;
750    /// # fn dummy() -> Result<MoltFloat,Exception> {
751    ///
752    /// let value = Value::from(12.34);
753    /// let flt = value.as_float()?;
754    /// assert_eq!(flt, 12.34);
755    ///
756    /// let value = Value::from("23.45");
757    /// let flt = value.as_float()?;
758    /// assert_eq!(flt, 23.45);
759    /// # Ok(1.0)
760    /// # }
761    /// ```
762    pub fn as_float(&self) -> Result<MoltFloat, Exception> {
763        // FIRST, if we have a float then just return it.
764        if let DataRep::Flt(flt) = *self.inner.data_rep.borrow() {
765            return Ok(flt);
766        }
767
768        // NEXT, Try to parse the string_rep as a float
769        let str = self.as_str();
770        let flt = Value::get_float(str)?;
771        *self.inner.data_rep.borrow_mut() = DataRep::Flt(flt);
772        Ok(flt)
773    }
774
775    /// Converts an string argument into a `MoltFloat`, returning an error on failure.
776    ///
777    /// Molt accepts any string acceptable to `str::parse<f64>` as a valid floating
778    /// point string.  Leading and trailing whitespace is ignored, and parsing is
779    /// case-insensitive.
780    ///
781    /// # Example
782    ///
783    /// ```
784    /// # use molt::types::*;
785    /// # fn dummy() -> Result<MoltFloat,Exception> {
786    /// let arg = "1e2";
787    /// let val = Value::get_float(arg)?;
788    /// # Ok(val)
789    /// # }
790    /// ```
791    pub fn get_float(arg: &str) -> Result<MoltFloat, Exception> {
792        let arg_trim = arg.trim().to_lowercase();
793
794        match arg_trim.parse::<MoltFloat>() {
795            Ok(flt) => Ok(flt),
796            Err(_) => molt_err!("expected floating-point number but got \"{}\"", arg),
797        }
798    }
799
800    /// Computes the string rep for a MoltFloat.
801    ///
802    /// TODO: This needs a lot of work, so that floating point outputs will parse back into
803    /// the same floating point numbers.
804    fn fmt_float(f: &mut std::fmt::Formatter, flt: MoltFloat) -> std::fmt::Result {
805        if flt == std::f64::INFINITY {
806            write!(f, "Inf")
807        } else if flt == std::f64::NEG_INFINITY {
808            write!(f, "-Inf")
809        } else if flt.is_nan() {
810            write!(f, "NaN")
811        } else {
812            // TODO: Needs improvement.
813            write!(f, "{}", flt)
814        }
815    }
816
817    /// Tries to return the `Value` as an `Rc<MoltList>`, parsing the
818    /// value's string representation if necessary.
819    ///
820    /// # Example
821    ///
822    /// ```
823    /// use std::rc::Rc;
824    /// use molt::types::Value;
825    /// use molt::types::MoltList;
826    /// use molt::types::Exception;
827    /// # fn dummy() -> Result<String,Exception> {
828    ///
829    /// let value = Value::from("1234 abc");
830    /// let list: Rc<MoltList> = value.as_list()?;
831    /// assert_eq!(list.len(), 2);
832    ///
833    /// assert_eq!(list[0], Value::from("1234"));
834    /// assert_eq!(list[1], Value::from("abc"));
835    ///
836    /// # Ok("dummy".to_string())
837    /// # }
838    /// ```
839    pub fn as_list(&self) -> Result<Rc<MoltList>, Exception> {
840        // FIRST, if we have the desired type, return it.
841        if let DataRep::List(list) = &*self.inner.data_rep.borrow() {
842            return Ok(list.clone());
843        }
844
845        // NEXT, try to parse the string_rep as a list.
846        let str = self.as_str();
847        let list = Rc::new(get_list(str)?);
848        *self.inner.data_rep.borrow_mut() = DataRep::List(list.clone());
849
850        Ok(list)
851    }
852
853    /// Tries to return the `Value` as a `MoltList`, parsing the
854    /// value's string representation if necessary.
855    ///
856    /// Use [`as_list`](#method.as_list) when simply referring to the list's content;
857    /// use this method when constructing a new list from the old one.
858    ///
859    /// # Example
860    ///
861    /// ```
862    /// use molt::types::Value;
863    /// use molt::types::MoltList;
864    /// use molt::types::Exception;
865    /// # fn dummy() -> Result<String,Exception> {
866    ///
867    /// let value = Value::from("1234 abc");
868    /// let list: MoltList = value.to_list()?;
869    /// assert_eq!(list.len(), 2);
870    ///
871    /// assert_eq!(list[0], Value::from("1234"));
872    /// assert_eq!(list[1], Value::from("abc"));
873    ///
874    /// # Ok("dummy".to_string())
875    /// # }
876    /// ```
877    pub fn to_list(&self) -> Result<MoltList, Exception> {
878        Ok((&*self.as_list()?).to_owned())
879    }
880
881    /// Tries to return the `Value` as an `Rc<Script>`, parsing the
882    /// value's string representation if necessary.
883    ///
884    /// For internal use only.  Note: this is the normal way to convert a script string
885    /// into a Script object.  Converting the Script back into a Tcl string is not
886    /// currently supported.
887    pub(crate) fn as_script(&self) -> Result<Rc<Script>, Exception> {
888        // FIRST, if we have the desired type, return it.
889        if let DataRep::Script(script) = &*self.inner.data_rep.borrow() {
890            return Ok(script.clone());
891        }
892
893        // NEXT, try to parse the string_rep as a script.
894        let str = self.as_str();
895        let script = Rc::new(parser::parse(str)?);
896        *self.inner.data_rep.borrow_mut() = DataRep::Script(script.clone());
897
898        Ok(script)
899    }
900
901    /// Returns the `Value` as an `Rc<VarName>`, parsing the
902    /// value's string representation if necessary.  This type is usually hidden by the
903    /// `Interp`'s `var` and `set_var` methods, which use it implicitly; however it is
904    /// available to extension authors if need be.
905    ///
906    /// # Example
907    ///
908    /// ```
909    /// use molt::types::{Value, VarName};
910    ///
911    /// let value = Value::from("my_var");
912    /// let var_name = value.as_var_name();
913    /// assert_eq!(var_name.name(), "my_var");
914    /// assert_eq!(var_name.index(), None);
915    ///
916    /// let value = Value::from("my_array(1)");
917    /// let var_name = value.as_var_name();
918    /// assert_eq!(var_name.name(), "my_array");
919    /// assert_eq!(var_name.index(), Some("1"));
920    /// ```
921    pub fn as_var_name(&self) -> Rc<VarName> {
922        // FIRST, if we have the desired type, return it.
923        if let DataRep::VarName(var_name) = &*self.inner.data_rep.borrow() {
924            return var_name.clone();
925        }
926
927        // NEXT, try to parse the string_rep as a variable name.
928        let var_name = Rc::new(parser::parse_varname_literal(self.as_str()));
929
930        *self.inner.data_rep.borrow_mut() = DataRep::VarName(var_name.clone());
931        var_name
932    }
933
934    /// Creates a new `Value` containing the given value of some user type.
935    ///
936    /// The user type must meet certain constraints; see the
937    /// [module level documentation](index.html) for details on
938    /// how to define an external type for use with Molt.
939    ///
940    /// # Example
941    ///
942    /// Suppose we have a type `HexColor` that meets the constraints; we can create
943    /// a `Value` containing one as follows.  Notice that the `Value` ownership of its input:
944    ///
945    /// ```ignore
946    /// let color: HexColor::new(0x11u8, 0x22u8, 0x33u8);
947    /// let value = Value::from_other(color);
948    ///
949    /// // Retrieve the value's string rep.
950    /// assert_eq!(value.as_str(), "#112233");
951    /// ```
952    ///
953    /// See [`Value::as_other`](#method.as_other) and
954    /// [`Value::as_copy`](#method.as_copy) for examples of how to
955    /// retrieve a `MyType` value from a `Value`.
956    pub fn from_other<T: 'static>(value: T) -> Value
957    where
958        T: Display + Debug,
959    {
960        Value::inner_from_data(DataRep::Other(Rc::new(value)))
961    }
962
963    /// Tries to interpret the `Value` as a value of external type `T`, parsing
964    /// the string representation if necessary.
965    ///
966    /// The user type must meet certain constraints; see the
967    /// [module level documentation](index.html) for details on
968    /// how to define an external type for use with Molt.
969    ///
970    /// # Return Value
971    ///
972    /// The value is returned as an `Rc<T>`, as this allows the client to
973    /// use the value freely and clone it efficiently if needed.
974    ///
975    /// This method returns `Option<Rc<T>>` rather than `Result<Rc<T>,Exception>`
976    /// because it is up to the caller to provide a meaningful error message.
977    /// It is normal for externally defined types to wrap this function in a function
978    /// that does so; see the [module level documentation](index.html) for an example.
979    ///
980    /// # Example
981    ///
982    /// Suppose we have a type `HexColor` that meets the constraints; we can create
983    /// a `Value` containing one and retrieve it as follows.
984    ///
985    /// ```ignore
986    /// // Just a normal Molt string
987    /// let value = Value::from("#112233");
988    ///
989    /// // Retrieve it as an Option<Rc<HexColor>>:
990    /// let color = value.as_other::<HexColor>()
991    ///
992    /// if color.is_some() {
993    ///     let color = color.unwrap();
994    ///     let r = *color.red();
995    ///     let g = *color.green();
996    ///     let b = *color.blue();
997    /// }
998    /// ```
999    pub fn as_other<T: 'static>(&self) -> Option<Rc<T>>
1000    where
1001        T: Display + Debug + FromStr,
1002    {
1003        // FIRST, if we have the desired type, return it.
1004        if let DataRep::Other(other) = &*self.inner.data_rep.borrow() {
1005            // other is an &Rc<MoltAny>
1006            if let Ok(out) = other.clone().downcast::<T>() {
1007                return Some(out);
1008            }
1009        }
1010
1011        // NEXT, can we parse it as a T?  If so, save it back to
1012        // the data_rep, and return it.
1013        let str = self.as_str();
1014
1015        if let Ok(tval) = str.parse::<T>() {
1016            let tval = Rc::new(tval);
1017            let out = tval.clone();
1018            *self.inner.data_rep.borrow_mut() = DataRep::Other(Rc::new(tval));
1019            return Some(out);
1020        }
1021
1022        // NEXT, we couldn't do it.
1023        None
1024    }
1025
1026    /// Tries to interpret the `Value` as a value of type `T`, parsing the string
1027    /// representation if necessary, and returning a copy.
1028    ///
1029    /// The user type must meet certain constraints; and in particular it must
1030    /// implement `Copy`. See the [module level documentation](index.html) for details on
1031    /// how to define an external type for use with Molt.
1032    ///
1033    /// This method returns `Option` rather than `Result` because it is up
1034    /// to the caller to provide a meaningful error message.  It is normal
1035    /// for externally defined types to wrap this function in a function
1036    /// that does so.
1037    ///
1038    /// # Example
1039    ///
1040    /// Suppose we have a type `HexColor` that meets the normal external type
1041    /// constraints and also supports copy; we can create a `Value` containing one and
1042    /// retrieve it as follows.
1043    ///
1044    /// ```ignore
1045    /// // Just a normal Molt string
1046    /// let value = Value::from("#112233");
1047    ///
1048    /// // Retrieve it as an Option<HexColor>:
1049    /// let color = value.as_copy::<HexColor>()
1050    ///
1051    /// if color.is_some() {
1052    ///     let color = color.unwrap();
1053    ///     let r = color.red();
1054    ///     let g = color.green();
1055    ///     let b = color.blue();
1056    /// }
1057    /// ```
1058    pub fn as_copy<T: 'static>(&self) -> Option<T>
1059    where
1060        T: Display + Debug + FromStr + Copy,
1061    {
1062        // FIRST, if we have the desired type, return it.
1063        if let DataRep::Other(other) = &*self.inner.data_rep.borrow() {
1064            // other is an &Rc<MoltAny>
1065            if let Ok(out) = other.clone().downcast::<T>() {
1066                return Some(*out);
1067            }
1068        }
1069
1070        // NEXT, can we parse it as a T?  If so, save it back to
1071        // the data_rep, and return it.
1072        let str = self.as_str();
1073
1074        if let Ok(tval) = str.parse::<T>() {
1075            let tval = Rc::new(tval);
1076            let out = tval.clone();
1077            *self.inner.data_rep.borrow_mut() = DataRep::Other(Rc::new(tval));
1078            return Some(*out);
1079        }
1080
1081        // NEXT, we couldn't do it.
1082        None
1083    }
1084
1085    /// For use by `expr::expr` in parsing out `Values`.
1086    pub(crate) fn already_number(&self) -> Option<Datum> {
1087        let iref = self.inner.data_rep.borrow();
1088
1089        match *iref {
1090            DataRep::Flt(flt) => Some(Datum::float(flt)),
1091            DataRep::Int(int) => Some(Datum::int(int)),
1092            _ => None,
1093        }
1094    }
1095}
1096
1097//-----------------------------------------------------------------------------
1098// The MoltAny Trait: a tool for handling external types.
1099
1100/// This trait allows us to except "other" types, and still compute their
1101/// string rep on demand.
1102trait MoltAny: Any + Display + Debug {
1103    fn as_any(&self) -> &dyn Any;
1104    fn as_any_mut(&mut self) -> &mut dyn Any;
1105    fn into_any(self: Box<Self>) -> Box<dyn Any>;
1106}
1107
1108impl dyn MoltAny {
1109    /// Is this value a value of the desired type?
1110    pub fn is<T: 'static>(&self) -> bool {
1111        TypeId::of::<T>() == self.type_id()
1112    }
1113
1114    /// Downcast an `Rc<MoltAny>` to an `Rc<T>`
1115    fn downcast<T: 'static>(self: Rc<Self>) -> Result<Rc<T>, Rc<Self>> {
1116        if self.is::<T>() {
1117            unsafe { Ok(Rc::from_raw(Rc::into_raw(self) as _)) }
1118        } else {
1119            Err(self)
1120        }
1121    }
1122}
1123
1124impl<T: Any + Display + Debug> MoltAny for T {
1125    fn as_any(&self) -> &dyn Any {
1126        self
1127    }
1128    fn as_any_mut(&mut self) -> &mut dyn Any {
1129        self
1130    }
1131    fn into_any(self: Box<Self>) -> Box<dyn Any> {
1132        self
1133    }
1134}
1135
1136//-----------------------------------------------------------------------------
1137// DataRep enum: a sum type for the different kinds of data_reps.
1138
1139// The data representation for Values.
1140#[derive(Clone, Debug)]
1141enum DataRep {
1142    /// A Boolean
1143    Bool(bool),
1144
1145    /// A Molt Dictionary
1146    Dict(Rc<MoltDict>),
1147
1148    /// A Molt integer
1149    Int(MoltInt),
1150
1151    /// A Molt float
1152    Flt(MoltFloat),
1153
1154    /// A Molt List
1155    List(Rc<MoltList>),
1156
1157    /// A Script
1158    Script(Rc<Script>),
1159
1160    /// A Variable Name
1161    VarName(Rc<VarName>),
1162
1163    /// An external data type
1164    Other(Rc<dyn MoltAny>),
1165
1166    /// The Value has no data rep at present.
1167    None,
1168}
1169
1170impl Display for DataRep {
1171    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1172        match self {
1173            DataRep::Bool(flag) => write!(f, "{}", if *flag { 1 } else { 0 }),
1174            DataRep::Dict(dict) => write!(f, "{}", dict_to_string(&*dict)),
1175            DataRep::Int(int) => write!(f, "{}", int),
1176            DataRep::Flt(flt) => Value::fmt_float(f, *flt),
1177            DataRep::List(list) => write!(f, "{}", list_to_string(&*list)),
1178            DataRep::Script(script) => write!(f, "{:?}", script),
1179            DataRep::VarName(var_name) => write!(f, "{:?}", var_name),
1180            DataRep::Other(other) => write!(f, "{}", other),
1181            DataRep::None => write!(f, ""),
1182        }
1183    }
1184}
1185
1186#[cfg(test)]
1187mod tests {
1188    use super::*;
1189    use crate::dict::dict_new;
1190    use std::fmt;
1191    use std::str::FromStr;
1192
1193    #[test]
1194    fn from_string() {
1195        // Using From<String>
1196        let val = Value::from("xyz".to_string());
1197        assert_eq!(&val.to_string(), "xyz");
1198
1199        // Using Into
1200        let val: Value = String::from("Fred").into();
1201        assert_eq!(&val.to_string(), "Fred");
1202    }
1203
1204    #[test]
1205    fn from_str_ref() {
1206        // Using From<&str>
1207        let val = Value::from("xyz");
1208        assert_eq!(&val.to_string(), "xyz");
1209
1210        // Using Into
1211        let val: Value = "Fred".into();
1212        assert_eq!(&val.to_string(), "Fred");
1213    }
1214
1215    #[test]
1216    fn clone_string() {
1217        // Values with just string reps can be cloned and have equal string reps.
1218        let val = Value::from("abc");
1219        let val2 = val.clone();
1220        assert_eq!(*val.to_string(), *val2.to_string());
1221    }
1222
1223    #[test]
1224    fn as_str() {
1225        let val = Value::from("abc");
1226        assert_eq!(val.as_str(), "abc");
1227
1228        let val2 = val.clone();
1229        assert_eq!(val.as_str(), val2.as_str());
1230    }
1231
1232    #[test]
1233    fn compare() {
1234        let val = Value::from("123");
1235        let val2 = Value::from(123);
1236        let val3 = Value::from(456);
1237
1238        assert_eq!(val, val2);
1239        assert_ne!(val, val3);
1240    }
1241
1242    #[test]
1243    fn from_bool() {
1244        // Using From<bool>
1245        let val = Value::from(true);
1246        assert_eq!(&val.to_string(), "1");
1247
1248        let val = Value::from(false);
1249        assert_eq!(&val.to_string(), "0");
1250    }
1251
1252    #[test]
1253    fn as_bool() {
1254        // Can convert string to bool.
1255        let val = Value::from("true");
1256        assert_eq!(val.as_bool(), Ok(true));
1257
1258        // Non-zero numbers are true; zero is false.
1259        let val = Value::from(5);
1260        assert_eq!(val.as_bool(), Ok(true));
1261
1262        let val = Value::from(0);
1263        assert_eq!(val.as_bool(), Ok(false));
1264
1265        let val = Value::from(5.5);
1266        assert_eq!(val.as_bool(), Ok(true));
1267
1268        let val = Value::from(0.0);
1269        assert_eq!(val.as_bool(), Ok(false));
1270    }
1271
1272    #[test]
1273    fn get_bool() {
1274        // Test the underlying boolean value parser.
1275        assert_eq!(Ok(true), Value::get_bool("1"));
1276        assert_eq!(Ok(true), Value::get_bool("true"));
1277        assert_eq!(Ok(true), Value::get_bool("yes"));
1278        assert_eq!(Ok(true), Value::get_bool("on"));
1279        assert_eq!(Ok(true), Value::get_bool("TRUE"));
1280        assert_eq!(Ok(true), Value::get_bool("YES"));
1281        assert_eq!(Ok(true), Value::get_bool("ON"));
1282        assert_eq!(Ok(false), Value::get_bool("0"));
1283        assert_eq!(Ok(false), Value::get_bool("false"));
1284        assert_eq!(Ok(false), Value::get_bool("no"));
1285        assert_eq!(Ok(false), Value::get_bool("off"));
1286        assert_eq!(Ok(false), Value::get_bool("FALSE"));
1287        assert_eq!(Ok(false), Value::get_bool("NO"));
1288        assert_eq!(Ok(false), Value::get_bool("OFF"));
1289        assert_eq!(Ok(true), Value::get_bool(" true "));
1290        assert_eq!(
1291            Value::get_bool("nonesuch"),
1292            molt_err!("expected boolean but got \"nonesuch\"")
1293        );
1294        assert_eq!(
1295            Value::get_bool(" Nonesuch "),
1296            molt_err!("expected boolean but got \" Nonesuch \"")
1297        );
1298    }
1299
1300    #[test]
1301    fn from_as_dict() {
1302        // NOTE: we aren't testing dict formatting and parsing here.
1303        // We *are* testing that Value can convert dicts to and from strings.
1304        // and back again.
1305        let mut dict = dict_new();
1306        dict.insert(Value::from("abc"), Value::from("def"));
1307        let dictval = Value::from(dict);
1308        assert_eq!(dictval.as_str(), "abc def");
1309
1310        let dictval = Value::from("qrs xyz");
1311        let result = dictval.as_dict();
1312
1313        assert!(result.is_ok());
1314
1315        if let Ok(rcdict) = result {
1316            assert_eq!(rcdict.len(), 1);
1317            assert_eq!(rcdict.get(&Value::from("qrs")), Some(&Value::from("xyz")));
1318        }
1319    }
1320
1321    #[test]
1322    fn to_dict() {
1323        let dictval = Value::from("qrs xyz");
1324        let result = dictval.to_dict();
1325
1326        assert!(result.is_ok());
1327
1328        if let Ok(dict) = result {
1329            assert_eq!(dict.len(), 1);
1330            assert_eq!(dict.get(&Value::from("qrs")), Some(&Value::from("xyz")));
1331        }
1332    }
1333
1334    #[test]
1335    fn from_as_int() {
1336        let val = Value::from(5);
1337        assert_eq!(val.as_str(), "5");
1338        assert_eq!(val.as_int(), Ok(5));
1339        assert_eq!(val.as_float(), Ok(5.0));
1340
1341        let val = Value::from("7");
1342        assert_eq!(val.as_str(), "7");
1343        assert_eq!(val.as_int(), Ok(7));
1344        assert_eq!(val.as_float(), Ok(7.0));
1345
1346        // TODO: Note, 7.0 might not get converted to "7" long term.
1347        // In Standard TCL, its string_rep would be "7.0".  Need to address
1348        // MoltFloat formatting/parsing.
1349        let val = Value::from(7.0);
1350        assert_eq!(val.as_str(), "7");
1351        assert_eq!(val.as_int(), Ok(7));
1352        assert_eq!(val.as_float(), Ok(7.0));
1353
1354        let val = Value::from("abc");
1355        assert_eq!(val.as_int(), molt_err!("expected integer but got \"abc\""));
1356    }
1357
1358    #[test]
1359    fn get_int() {
1360        // Test the internal integer parser
1361        assert_eq!(Value::get_int("1"), Ok(1));
1362        assert_eq!(Value::get_int("-1"), Ok(-1));
1363        assert_eq!(Value::get_int("+1"), Ok(1));
1364        assert_eq!(Value::get_int("0xFF"), Ok(255));
1365        assert_eq!(Value::get_int("+0xFF"), Ok(255));
1366        assert_eq!(Value::get_int("-0xFF"), Ok(-255));
1367        assert_eq!(Value::get_int(" 1 "), Ok(1));
1368
1369        assert_eq!(Value::get_int(""), molt_err!("expected integer but got \"\""));
1370        assert_eq!(Value::get_int("a"), molt_err!("expected integer but got \"a\""));
1371        assert_eq!(Value::get_int("0x"), molt_err!("expected integer but got \"0x\""));
1372        assert_eq!(
1373            Value::get_int("0xABGG"),
1374            molt_err!("expected integer but got \"0xABGG\"")
1375        );
1376        assert_eq!(
1377            Value::get_int(" abc "),
1378            molt_err!("expected integer but got \" abc \"")
1379        );
1380    }
1381
1382    #[test]
1383    fn from_as_float() {
1384        let val = Value::from(12.5);
1385        assert_eq!(val.as_str(), "12.5");
1386        assert_eq!(val.as_int(), molt_err!("expected integer but got \"12.5\""));
1387        assert_eq!(val.as_float(), Ok(12.5));
1388
1389        let val = Value::from("7.8");
1390        assert_eq!(val.as_str(), "7.8");
1391        assert_eq!(val.as_int(), molt_err!("expected integer but got \"7.8\""));
1392        assert_eq!(val.as_float(), Ok(7.8));
1393
1394        // TODO: Problem here: tries to mutably borrow the data_rep to convert from int to string
1395        // while the data_rep is already mutably borrowed to convert the string to float.
1396        let val = Value::from(5);
1397        assert_eq!(val.as_float(), Ok(5.0));
1398
1399        let val = Value::from("abc");
1400        assert_eq!(
1401            val.as_float(),
1402            molt_err!("expected floating-point number but got \"abc\"")
1403        );
1404    }
1405
1406    #[test]
1407    fn get_float() {
1408        // Test the internal float parser.
1409        // NOTE: At present, it relies on the standard Rust float parser, so only
1410        // check special case behavior.
1411        assert_eq!(Value::get_float("1"), Ok(1.0));
1412        assert_eq!(Value::get_float("2.3"), Ok(2.3));
1413        assert_eq!(Value::get_float(" 4.5 "), Ok(4.5));
1414        assert_eq!(Value::get_float("Inf"), Ok(std::f64::INFINITY));
1415
1416        assert_eq!(
1417            Value::get_float("abc"),
1418            molt_err!("expected floating-point number but got \"abc\"")
1419        );
1420        assert_eq!(
1421            Value::get_float(" abc "),
1422            molt_err!("expected floating-point number but got \" abc \"")
1423        );
1424    }
1425
1426    #[test]
1427    fn from_as_list() {
1428        // NOTE: we aren't testing list formatting and parsing here; that's done in list.rs.
1429        // We *are* testing that Value will use the list.rs code to convert strings to lists
1430        // and back again.
1431        let listval = Value::from(vec![Value::from("abc"), Value::from("def")]);
1432        assert_eq!(listval.as_str(), "abc def");
1433
1434        let listval = Value::from("qrs xyz");
1435        let result = listval.as_list();
1436
1437        assert!(result.is_ok());
1438
1439        if let Ok(rclist) = result {
1440            assert_eq!(rclist.len(), 2);
1441            assert_eq!(rclist[0].to_string(), "qrs".to_string());
1442            assert_eq!(rclist[1].to_string(), "xyz".to_string());
1443        }
1444    }
1445
1446    #[test]
1447    fn to_list() {
1448        let listval = Value::from(vec![Value::from("abc"), Value::from("def")]);
1449        let result = listval.to_list();
1450
1451        assert!(result.is_ok());
1452        let list: MoltList = result.expect("an owned list");
1453
1454        assert_eq!(list.len(), 2);
1455        assert_eq!(list[0].to_string(), "abc".to_string());
1456        assert_eq!(list[1].to_string(), "def".to_string());
1457    }
1458
1459    #[test]
1460    fn as_script() {
1461        let val = Value::from("a");
1462        assert!(val.as_script().is_ok());
1463
1464        let val = Value::from("a {b");
1465        assert_eq!(val.as_script(), molt_err_uncompleted!("missing close-brace"));
1466    }
1467
1468    #[test]
1469    fn as_var_name() {
1470        let val = Value::from("a");
1471        assert_eq!(val.as_var_name().name(), "a");
1472        assert_eq!(val.as_var_name().index(), None);
1473
1474        let val = Value::from("a(b)");
1475        assert_eq!(val.as_var_name().name(), "a");
1476        assert_eq!(val.as_var_name().index(), Some("b"));
1477    }
1478
1479    #[test]
1480    fn from_value_slice() {
1481        // NOTE: we aren't testing list formatting and parsing here; that's done in list.rs.
1482        // We *are* testing that Value will use the list.rs code to convert strings to lists
1483        // and back again.
1484        let array = [Value::from("abc"), Value::from("def")];
1485        let listval = Value::from(&array[..]);
1486        assert_eq!(listval.as_str(), "abc def");
1487    }
1488
1489    #[test]
1490    fn from_to_flavor() {
1491        // Give a Flavor, get an Rc<Flavor> back.
1492        let myval = Value::from_other(Flavor::SALTY);
1493        let result = myval.as_other::<Flavor>();
1494        assert!(result.is_some());
1495        let out = result.unwrap();
1496        assert_eq!(*out, Flavor::SALTY);
1497
1498        // Give a String, get an Rc<Flavor> back.
1499        let myval = Value::from("sweet");
1500        let result = myval.as_other::<Flavor>();
1501        assert!(result.is_some());
1502        let out = result.unwrap();
1503        assert_eq!(*out, Flavor::SWEET);
1504
1505        // Flavor is Copy, so get a Flavor back
1506        let myval = Value::from_other(Flavor::SALTY);
1507        let result = myval.as_copy::<Flavor>();
1508        assert!(result.is_some());
1509        let out = result.unwrap();
1510        assert_eq!(out, Flavor::SALTY);
1511    }
1512
1513    #[test]
1514    fn already_number() {
1515        // Can retrieve a DataRep::Int as a Datum::Int.
1516        let value = Value::from(123);
1517        let out = value.already_number();
1518        assert!(out.is_some());
1519        assert_eq!(out.unwrap(), Datum::int(123));
1520
1521        // Can retrieve a DataRep::Flt as a Datum::Flt.
1522        let value = Value::from(45.6);
1523        let out = value.already_number();
1524        assert!(out.is_some());
1525        assert_eq!(out.unwrap(), Datum::float(45.6));
1526
1527        // Other values, None.
1528        let value = Value::from("123");
1529        assert!(value.already_number().is_none());
1530    }
1531
1532    // Sample external type, used for testing.
1533
1534    #[derive(Debug, PartialEq, Copy, Clone)]
1535    pub enum Flavor {
1536        SALTY,
1537        SWEET,
1538    }
1539
1540    impl FromStr for Flavor {
1541        type Err = String;
1542
1543        fn from_str(value: &str) -> Result<Self, Self::Err> {
1544            let value = value.to_lowercase();
1545
1546            if value == "salty" {
1547                Ok(Flavor::SALTY)
1548            } else if value == "sweet" {
1549                Ok(Flavor::SWEET)
1550            } else {
1551                Err("Not a flavor string".to_string())
1552            }
1553        }
1554    }
1555
1556    impl fmt::Display for Flavor {
1557        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1558            if *self == Flavor::SALTY {
1559                write!(f, "salty")
1560            } else {
1561                write!(f, "sweet")
1562            }
1563        }
1564    }
1565}