pub enum Value {
Nil,
Null,
Bool(bool),
Number(Number),
Char(char),
String(Box<str>),
Symbol(Box<str>),
Keyword(Box<str>),
Bytes(Box<[u8]>),
Cons(Cons),
Vector(Box<[Value]>),
}
Expand description
Represents an S-expression value.
See the lexpr::value
module documentation for usage examples.
Variants§
Nil
The special “nil” value.
This is kind of an oddball value. In traditional Lisps (e.g., Common
Lisp or Emacs Lisp) the empty list can be written as the symbol nil
,
while in Scheme, nil
is just a regular symbol. Furthermore,
traditional Lisps don’t have a separate boolean data type, and represent
true and false by the symbols t
and nil
instead. The lexpr
parser
can be instructed to parse the nil
symbol as the Nil
value (see
NilSymbol::Special
), allowing to choose its representation when
converting to text again (see NilSyntax
). Note that the empty list,
when written as ()
or implicitly constructed as a list terminator, is
always parsed as Value::Null
, not Value::Nil
.
In addition to being useful for conversions between S-expression
variants, this value is also potentially returned when using the square
bracket indexing operator on Value
.
Null
The empty list.
This value terminates a chain of cons cells forming a proper list.
Bool(bool)
A boolean value.
Number(Number)
A number.
Char(char)
A character.
String(Box<str>)
A string.
Symbol(Box<str>)
A symbol.
Keyword(Box<str>)
A keyword.
Bytes(Box<[u8]>)
A byte vector.
Cons(Cons)
Represents a Lisp “cons cell”.
Cons cells are often used to form singly-linked lists.
let v = sexp!((a list 1 2 3));
assert!(v.is_cons());
assert_eq!(v[4], sexp!(3));
Vector(Box<[Value]>)
A Lisp vector.
Implementations§
source§impl Value
impl Value
sourcepub fn keyword(name: impl Into<Box<str>>) -> Self
pub fn keyword(name: impl Into<Box<str>>) -> Self
Construct a keyword, given its name.
let value = Value::keyword("foo");
assert!(value.is_keyword());
assert_eq!(value.as_keyword().unwrap(), "foo");
sourcepub fn string(s: impl Into<Box<str>>) -> Self
pub fn string(s: impl Into<Box<str>>) -> Self
Construct a string.
let value = Value::string("foo");
assert!(value.is_string());
assert_eq!(value.as_str().unwrap(), "foo");
sourcepub fn bytes(bv: impl Into<Box<[u8]>>) -> Self
pub fn bytes(bv: impl Into<Box<[u8]>>) -> Self
Construct a byte vector.
let value = Value::bytes(b"foo" as &[u8]);
assert!(value.is_bytes());
assert_eq!(value.as_bytes().unwrap(), b"foo");
sourcepub fn cons<T, U>(car: T, cdr: U) -> Selfwhere
T: Into<Value>,
U: Into<Value>,
pub fn cons<T, U>(car: T, cdr: U) -> Selfwhere T: Into<Value>, U: Into<Value>,
Create a cons cell given its car
and cdr
fields.
let value = Value::cons(1, Value::Null);
assert!(value.is_cons());
assert_eq!(value.as_pair().unwrap(), (&Value::from(1), &Value::Null));
Note that you can also construct a cons cell from a Rust pair via the
From
trait:
let value = Value::from((42, "answer"));
assert!(value.is_cons());
assert_eq!(value.as_pair().unwrap(), (&Value::from(42), &Value::string("answer")));
sourcepub fn list<I>(elements: I) -> Selfwhere
I: IntoIterator,
I::Item: Into<Value>,
pub fn list<I>(elements: I) -> Selfwhere I: IntoIterator, I::Item: Into<Value>,
Create a list value from elements convertible into Value
.
assert_eq!(Value::list(vec![1, 2, 3]), sexp!((1 2 3)));
sourcepub fn is_dotted_list(&self) -> bool
pub fn is_dotted_list(&self) -> bool
Returns true if the value is a dotted (improper) list.
Note that all values that are not pairs are considered dotted lists.
let list = sexp!((1 2 3));
assert!(!list.is_dotted_list());
let dotted = sexp!((1 2 . 3));
assert!(dotted.is_dotted_list());
sourcepub fn append<I, T>(elements: I, tail: T) -> Selfwhere
I: IntoIterator,
I::Item: Into<Value>,
T: Into<Value>,
pub fn append<I, T>(elements: I, tail: T) -> Selfwhere I: IntoIterator, I::Item: Into<Value>, T: Into<Value>,
Create a list value from elements convertible into Value
, using a
given value as a tail.
assert_eq!(Value::append(vec![1u32, 2], 3), sexp!((1 2 . 3)));
assert_eq!(Value::append(vec![1u32, 2, 3], sexp!((4 5))), sexp!((1 2 3 4 5)));
sourcepub fn vector<I>(elements: I) -> Selfwhere
I: IntoIterator,
I::Item: Into<Value>,
pub fn vector<I>(elements: I) -> Selfwhere I: IntoIterator, I::Item: Into<Value>,
Create a vector value from elements convertible into Value
.
assert_eq!(Value::vector(vec![1u32, 2, 3]), sexp!(#(1 2 3)));
sourcepub fn is_string(&self) -> bool
pub fn is_string(&self) -> bool
Returns true if the value is a String. Returns false otherwise.
For any Value on which is_string
returns true, as_str
is guaranteed
to return the string slice.
let v = sexp!(((a . "some string") (b . #f)));
assert!(v["a"].is_string());
// The boolean `false` is not a string.
assert!(!v["b"].is_string());
sourcepub fn as_str(&self) -> Option<&str>
pub fn as_str(&self) -> Option<&str>
If the value is a String, returns the associated str. Returns None
otherwise.
let v = sexp!(((a . "some string") (b . #f)));
assert_eq!(v["a"].as_str(), Some("some string"));
// The boolean `false` is not a string.
assert_eq!(v["b"].as_str(), None);
// S-expression values are printed in S-expression
// representation, so strings are in quotes.
// The value is: "some string"
println!("The value is: {}", v["a"]);
// Rust strings are printed without quotes.
//
// The value is: some string
println!("The value is: {}", v["a"].as_str().unwrap());
sourcepub fn is_symbol(&self) -> bool
pub fn is_symbol(&self) -> bool
Returns true if the value is a symbol. Returns false otherwise.
For any Value on which is_symbol
returns true, as_symbol
is guaranteed
to return the string slice.
let v = sexp!((#:foo bar "baz"));
assert!(v[1].is_symbol());
// Keywords and strings are not symbols.
assert!(!v[0].is_symbol());
assert!(!v[2].is_symbol());
sourcepub fn as_symbol(&self) -> Option<&str>
pub fn as_symbol(&self) -> Option<&str>
If the value is a symbol, returns the associated str. Returns None
otherwise.
let v = sexp!(foo);
assert_eq!(v.as_symbol(), Some("foo"));
sourcepub fn is_keyword(&self) -> bool
pub fn is_keyword(&self) -> bool
Returns true if the value is a keyword. Returns false otherwise.
For any Value on which is_keyword
returns true, as_keyword
is guaranteed
to return the string slice.
let v = sexp!((#:foo bar "baz"));
assert!(v[0].is_keyword());
// Symbols and strings are not keywords.
assert!(!v[1].is_keyword());
assert!(!v[2].is_keyword());
sourcepub fn as_keyword(&self) -> Option<&str>
pub fn as_keyword(&self) -> Option<&str>
If the value is a keyword, returns the associated str. Returns None
otherwise.
let v = sexp!(#:foo);
assert_eq!(v.as_keyword(), Some("foo"));
sourcepub fn as_name(&self) -> Option<&str>
pub fn as_name(&self) -> Option<&str>
Get the name of a symbol or keyword, or the value of a string.
This is useful if symbols, keywords and strings need to be treated equivalently in some context.
let kw = sexp!(#:foo);
assert_eq!(kw.as_name(), Some("foo"));
let sym = sexp!(bar);
assert_eq!(sym.as_name(), Some("bar"));
let s = sexp!("baz");
assert_eq!(s.as_name(), Some("baz"));
sourcepub fn is_bytes(&self) -> bool
pub fn is_bytes(&self) -> bool
Returns true if the value is a byte vector. Returns false otherwise.
For any Value on which is_bytes
returns true, as_bytes
is guaranteed
to return the byte slice.
let v = sexp!(((a . ,(b"some bytes" as &[u8])) (b . "string")));
assert!(v["a"].is_bytes());
// A string is not a byte vector.
assert!(!v["b"].is_bytes());
sourcepub fn as_bytes(&self) -> Option<&[u8]>
pub fn as_bytes(&self) -> Option<&[u8]>
If the value is a byte vector, returns the associated byte
slice. Returns None
otherwise.
let v = sexp!(((a . ,(b"some bytes" as &[u8])) (b . "string")));
assert_eq!(v["a"].as_bytes(), Some(b"some bytes" as &[u8]));
// A string is not a byte vector.
assert_eq!(v["b"].as_bytes(), None);
sourcepub fn as_number(&self) -> Option<&Number>
pub fn as_number(&self) -> Option<&Number>
For numbers, return a reference to them. For other values, return
None
.
sourcepub fn is_i64(&self) -> bool
pub fn is_i64(&self) -> bool
Returns true if the value is an integer between i64::MIN
and
i64::MAX
.
For any Value on which is_i64
returns true, as_i64
is guaranteed to
return the integer value.
let big = i64::max_value() as u64 + 10;
let v = sexp!(((a . 64) (b . ,big) (c . 256.0)));
assert!(v["a"].is_i64());
// Greater than i64::MAX.
assert!(!v["b"].is_i64());
// Numbers with a decimal point are not considered integers.
assert!(!v["c"].is_i64());
sourcepub fn is_u64(&self) -> bool
pub fn is_u64(&self) -> bool
Returns true if the value is an integer between zero and u64::MAX
.
For any Value on which is_u64
returns true, as_u64
is guaranteed to
return the integer value.
let v = sexp!(((a . 64) (b . -64) (c . 256.0)));
assert!(v["a"].is_u64());
// Negative integer.
assert!(!v["b"].is_u64());
// Numbers with a decimal point are not considered integers.
assert!(!v["c"].is_u64());
sourcepub fn is_f64(&self) -> bool
pub fn is_f64(&self) -> bool
Returns true if the value is a number that can be represented by f64.
For any Value on which is_f64
returns true, as_f64
is guaranteed to
return the floating point value.
Currently this function returns true if and only if both is_i64
and
is_u64
return false but this is not a guarantee in the future.
let v = sexp!(((a . 256.0) (b . 64) (c . -64)));
assert!(v["a"].is_f64());
// Integers.
assert!(!v["b"].is_f64());
assert!(!v["c"].is_f64());
sourcepub fn as_i64(&self) -> Option<i64>
pub fn as_i64(&self) -> Option<i64>
If the value is an integer, represent it as i64 if possible. Returns None otherwise.
let big = i64::max_value() as u64 + 10;
let v = sexp!(((a . 64) (b . ,big) (c . 256.0)));
assert_eq!(v["a"].as_i64(), Some(64));
assert_eq!(v["b"].as_i64(), None);
assert_eq!(v["c"].as_i64(), None);
sourcepub fn as_u64(&self) -> Option<u64>
pub fn as_u64(&self) -> Option<u64>
If the value is an integer, represent it as u64 if possible. Returns None otherwise.
let v = sexp!(((a . 64) (b . -64) (c . 256.0)));
assert_eq!(v["a"].as_u64(), Some(64));
assert_eq!(v["b"].as_u64(), None);
assert_eq!(v["c"].as_u64(), None);
sourcepub fn as_f64(&self) -> Option<f64>
pub fn as_f64(&self) -> Option<f64>
If the value is a number, represent it as f64 if possible. Returns None otherwise.
let v = sexp!(((a . 256.0) (b . 64) (c . -64)));
assert_eq!(v["a"].as_f64(), Some(256.0));
assert_eq!(v["b"].as_f64(), Some(64.0));
assert_eq!(v["c"].as_f64(), Some(-64.0));
sourcepub fn is_boolean(&self) -> bool
pub fn is_boolean(&self) -> bool
Returns true if the value is a Boolean. Returns false otherwise.
For any Value on which is_boolean
returns true, as_bool
is
guaranteed to return the boolean value.
let v = sexp!(((a . #f) (b . #nil)));
assert!(v["a"].is_boolean());
// The nil value is special, and not a boolean.
assert!(!v["b"].is_boolean());
sourcepub fn as_bool(&self) -> Option<bool>
pub fn as_bool(&self) -> Option<bool>
If the value is a Boolean
, returns the associated bool. Returns None
otherwise.
let v = sexp!(((a . #f) (b . "false")));
assert_eq!(v["a"].as_bool(), Some(false));
// The string `"false"` is a string, not a boolean.
assert_eq!(v["b"].as_bool(), None);
sourcepub fn is_char(&self) -> bool
pub fn is_char(&self) -> bool
Returns true if the value is a character. Returns false otherwise.
sourcepub fn as_char(&self) -> Option<char>
pub fn as_char(&self) -> Option<char>
If the value is a character, returns the associated char
. Returns None
otherwise.
let v = sexp!(((a . 'c') (b . "c")));
assert_eq!(v["a"].as_char(), Some('c'));
// The string `"c"` is a single-character string, not a character.
assert_eq!(v["b"].as_char(), None);
sourcepub fn is_nil(&self) -> bool
pub fn is_nil(&self) -> bool
Returns true if the value is Nil
. Returns false otherwise.
For any Value on which is_nil
returns true, as_nil
is guaranteed
to return Some(())
.
let v = sexp!(((a . #nil) (b . #f)));
assert!(v["a"].is_nil());
// The boolean `false` is not nil.
assert!(!v["b"].is_nil());
sourcepub fn as_nil(&self) -> Option<()>
pub fn as_nil(&self) -> Option<()>
If the value is Nil
, returns ()
. Returns None
otherwise.
let v = sexp!(((a . #nil) (b . #f) (c . ())));
assert_eq!(v["a"].as_nil(), Some(()));
// The boolean `false` is not nil.
assert_eq!(v["b"].as_nil(), None);
// Neither is the empty list.
assert_eq!(v["c"].as_nil(), None);
sourcepub fn is_cons(&self) -> bool
pub fn is_cons(&self) -> bool
Returns true if the value is a cons cell. Returns False
otherwise.
sourcepub fn as_cons(&self) -> Option<&Cons>
pub fn as_cons(&self) -> Option<&Cons>
If the value is a cons cell, returns a reference to it. Returns None
otherwise.
sourcepub fn as_cons_mut(&mut self) -> Option<&mut Cons>
pub fn as_cons_mut(&mut self) -> Option<&mut Cons>
If the value is a cons cell, returns a mutable reference to it. Returns
None
otherwise.
sourcepub fn as_pair(&self) -> Option<(&Value, &Value)>
pub fn as_pair(&self) -> Option<(&Value, &Value)>
If the value is a cons cell, return references to its car
and cdr
fields.
let cell = sexp!((foo . bar));
assert_eq!(cell.as_pair(), Some((&sexp!(foo), &sexp!(bar))));
assert_eq!(sexp!("not-a-pair").as_pair(), None);
sourcepub fn as_slice(&self) -> Option<&[Value]>
pub fn as_slice(&self) -> Option<&[Value]>
If the value is a vector, return a reference to its elements.
let v = sexp!(#(1 2 "three"));
let slice: &[Value] = &[sexp!(1), sexp!(2), sexp!("three")];
assert_eq!(v.as_slice(), Some(slice));
sourcepub fn as_slice_mut(&mut self) -> Option<&mut [Value]>
pub fn as_slice_mut(&mut self) -> Option<&mut [Value]>
If the value is a vector, return a mutable reference to its elements.
let mut v = sexp!(#(1 2 "three"));
v.as_slice_mut().unwrap()[2] = sexp!(3);
let slice: &[Value] = &[sexp!(1), sexp!(2), sexp!(3)];
assert_eq!(v.as_slice(), Some(slice));
sourcepub fn list_iter(&self) -> Option<ListIter<'_>>
pub fn list_iter(&self) -> Option<ListIter<'_>>
If the value is a list, return an iterator over the list elements.
If the value is not either a cons cell or Null
, None
is returned.
Note that the returned iterator has special behavior for improper lists, yielding the
element after the dot after returning None
the first time.
use lexpr::sexp;
let value = lexpr::from_str("(1 2 . 3)").unwrap();
let mut iter = value.list_iter().unwrap();
assert_eq!(iter.next(), Some(&sexp!(1)));
assert_eq!(iter.next(), Some(&sexp!(2)));
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), Some(&sexp!(3)));
assert_eq!(iter.next(), None);
sourcepub fn to_vec(&self) -> Option<Vec<Value>>
pub fn to_vec(&self) -> Option<Vec<Value>>
Attempts conversion to a vector, cloning the values.
For proper lists (including Value::Null
), this returns a vector of
values. If you want to handle improper list in a similar way, combine
as_cons
and the Cons::to_vec
method.
assert_eq!(sexp!((1 2 3)).to_vec(), Some(vec![sexp!(1), sexp!(2), sexp!(3)]));
assert_eq!(sexp!(()).to_vec(), Some(vec![]));
assert_eq!(sexp!((1 2 . 3)).to_vec(), None);
sourcepub fn to_ref_vec(&self) -> Option<Vec<&Value>>
pub fn to_ref_vec(&self) -> Option<Vec<&Value>>
Attempts conversion to a vector, taking references to the values.
For proper lists (including Value::Null
), this returns a vector of
value references. If you want to handle improper list in a similar way,
combine as_cons
and the Cons::to_ref_vec
method.
assert_eq!(sexp!((1 2 3)).to_ref_vec(), Some(vec![&sexp!(1), &sexp!(2), &sexp!(3)]));
assert_eq!(sexp!(()).to_ref_vec(), Some(vec![]));
assert_eq!(sexp!((1 2 . 3)).to_ref_vec(), None);
sourcepub fn get<I: Index>(&self, index: I) -> Option<&Value>
pub fn get<I: Index>(&self, index: I) -> Option<&Value>
Index into a S-expression list. A string or Value
value can
be used to access a value in an association list, and a usize
index can be used to access the n-th element of a list.
For indexing into association lists, the given string will match strings, symbols and keywords.
Returns None
if the type of self
does not match the type
of the index, for example if the index is a string and self
is not an association list. Also returns None
if the given
key does not exist in the map or the given index is not within
the bounds of the list; note that the tail of an improper list
is also considered out-of-bounds.
In Scheme terms, this method can be thought of a combination
of assoc-ref
and list-ref
, depending on the argument type. If
you want to look up a number in an association list, use an
Value
value containing that number.
let alist = sexp!((("A" . 65) (B . 66) (#:C . 67) (42 . "The answer")));
assert_eq!(alist.get("A").unwrap(), &sexp!(65));
assert_eq!(alist.get("B").unwrap(), &sexp!(66));
assert_eq!(alist.get("C").unwrap(), &sexp!(67));
assert_eq!(alist.get(sexp!(42)).unwrap(), &sexp!("The answer"));
let list = sexp!(("A" "B" "C"));
assert_eq!(*list.get(2).unwrap(), sexp!("C"));
assert_eq!(list.get("A"), None);
Square brackets can also be used to index into a value in a
more concise way. This returns the nil value in cases where
get
would have returned None
. See Index
for details.
let alist = sexp!((
("A" . ("a" "á" "à"))
("B" . ((b . 42) (c . 23)))
("C" . ("c" "ć" "ć̣" "ḉ"))
));
assert_eq!(alist["B"][0], sexp!((b . 42)));
assert_eq!(alist["C"][1], sexp!("ć"));
assert_eq!(alist["D"], sexp!(#nil));
assert_eq!(alist[0]["x"]["y"]["z"], sexp!(#nil));
Trait Implementations§
source§impl Display for Value
impl Display for Value
source§fn fmt(&self, f: &mut Formatter<'_>) -> Result
fn fmt(&self, f: &mut Formatter<'_>) -> Result
Display an S-expression value as a string.
let value = sexp!(((city "London") (street "10 Downing Street")));
// Compact format:
//
// ((city "London") (street "10 Downing Street"))
let compact = format!("{}", value);
assert_eq!(compact,
r#"((city "London") (street "10 Downing Street"))"#);
source§impl<I> Index<I> for Valuewhere
I: Index,
impl<I> Index<I> for Valuewhere I: Index,
source§fn index(&self, index: I) -> &Value
fn index(&self, index: I) -> &Value
Index into a lexpr::Value
using the syntax value[0]
or
value["k"]
.
Returns the nil value if the type of self
does not match the
type of the index, for example if the index is a string and
self
is not an association list. Also returns the nil value
if the given key does not exist in the assication list or the
given index is not within the bounds of the list.
Note that repeatedly indexing with a string is not possible, as the indexing operation returns the found association list entry, which is not an association list itself. This behavior, i.e. returning the whole entry including the key is due to the design decison of representing lists as Rust vectors.
Examples
let data = sexp!(((a . 42) (x . (y (z zz)))));
assert_eq!(data["x"], sexp!((y (z zz))));
assert_eq!(data["a"], sexp!(42)); // returns nil for undefined values
assert_eq!(data["b"], sexp!(#nil)); // does not panic