use std::fmt;
use std::io;
use std::str;
use crate::cons::{self, Cons};
use crate::number::Number;
pub use self::index::Index;
#[derive(Debug, PartialEq, Clone)]
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]>),
}
impl Value {
pub fn symbol(name: impl Into<Box<str>>) -> Self {
Value::Symbol(name.into())
}
pub fn keyword(name: impl Into<Box<str>>) -> Self {
Value::Keyword(name.into())
}
pub fn string(s: impl Into<Box<str>>) -> Self {
Value::String(s.into())
}
pub fn bytes(bv: impl Into<Box<[u8]>>) -> Self {
Value::Bytes(bv.into())
}
pub fn cons<T, U>(car: T, cdr: U) -> Self
where
T: Into<Value>,
U: Into<Value>,
{
Value::Cons(Cons::new(car, cdr))
}
pub fn list<I>(elements: I) -> Self
where
I: IntoIterator,
I::Item: Into<Value>,
{
Self::append(elements, Value::Null)
}
pub fn is_list(&self) -> bool {
match self {
Value::Null => true,
Value::Cons(pair) => pair.iter().all(|p| match p.cdr() {
Value::Null | Value::Cons(_) => true,
_ => false,
}),
_ => false,
}
}
pub fn is_dotted_list(&self) -> bool {
match self {
Value::Null => false,
Value::Cons(pair) => pair.iter().all(|p| match p.cdr() {
Value::Null => false,
_ => true,
}),
_ => true,
}
}
pub fn append<I, T>(elements: I, tail: T) -> Self
where
I: IntoIterator,
I::Item: Into<Value>,
T: Into<Value>,
{
let mut list = Cons::new(Value::Nil, Value::Null);
let mut pair = &mut list;
let mut have_value = false;
for item in elements {
if have_value {
pair.set_cdr(Value::from((Value::Nil, Value::Null)));
pair = pair.cdr_mut().as_cons_mut().unwrap();
}
pair.set_car(item.into());
have_value = true;
}
if have_value {
pair.set_cdr(tail.into());
Value::Cons(list)
} else {
tail.into()
}
}
pub fn vector<I>(elements: I) -> Self
where
I: IntoIterator,
I::Item: Into<Value>,
{
let v: Vec<_> = elements.into_iter().map(Into::into).collect();
Value::Vector(v.into_boxed_slice())
}
pub fn is_string(&self) -> bool {
self.as_str().is_some()
}
pub fn as_str(&self) -> Option<&str> {
match self {
Value::String(s) => Some(s),
_ => None,
}
}
pub fn is_symbol(&self) -> bool {
self.as_symbol().is_some()
}
pub fn as_symbol(&self) -> Option<&str> {
match self {
Value::Symbol(s) => Some(s),
_ => None,
}
}
pub fn is_keyword(&self) -> bool {
self.as_keyword().is_some()
}
pub fn as_keyword(&self) -> Option<&str> {
match self {
Value::Keyword(s) => Some(s),
_ => None,
}
}
pub fn as_name(&self) -> Option<&str> {
match self {
Value::Symbol(s) => Some(s),
Value::Keyword(s) => Some(s),
Value::String(s) => Some(s),
_ => None,
}
}
pub fn is_bytes(&self) -> bool {
self.as_bytes().is_some()
}
pub fn as_bytes(&self) -> Option<&[u8]> {
match self {
Value::Bytes(s) => Some(s),
_ => None,
}
}
pub fn is_number(&self) -> bool {
self.as_number().is_some()
}
pub fn as_number(&self) -> Option<&Number> {
match self {
Value::Number(n) => Some(n),
_ => None,
}
}
pub fn is_i64(&self) -> bool {
match self.as_number() {
Some(n) => n.is_i64(),
_ => false,
}
}
pub fn is_u64(&self) -> bool {
match self.as_number() {
Some(n) => n.is_u64(),
_ => false,
}
}
#[inline]
pub fn is_f64(&self) -> bool {
match self.as_number() {
Some(n) => n.is_f64(),
_ => false,
}
}
#[inline]
pub fn as_i64(&self) -> Option<i64> {
self.as_number().and_then(Number::as_i64)
}
pub fn as_u64(&self) -> Option<u64> {
self.as_number().and_then(Number::as_u64)
}
pub fn as_f64(&self) -> Option<f64> {
self.as_number().and_then(Number::as_f64)
}
pub fn is_boolean(&self) -> bool {
self.as_bool().is_some()
}
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(b) => Some(*b),
_ => None,
}
}
pub fn is_char(&self) -> bool {
self.as_char().is_some()
}
pub fn as_char(&self) -> Option<char> {
match self {
Value::Char(c) => Some(*c),
_ => None,
}
}
pub fn is_nil(&self) -> bool {
self.as_nil().is_some()
}
pub fn as_nil(&self) -> Option<()> {
match self {
Value::Nil => Some(()),
_ => None,
}
}
pub fn is_null(&self) -> bool {
self.as_null().is_some()
}
pub fn as_null(&self) -> Option<()> {
match self {
Value::Null => Some(()),
_ => None,
}
}
pub fn is_cons(&self) -> bool {
match self {
Value::Cons(_) => true,
_ => false,
}
}
pub fn as_cons(&self) -> Option<&Cons> {
match self {
Value::Cons(pair) => Some(pair),
_ => None,
}
}
pub fn as_cons_mut(&mut self) -> Option<&mut Cons> {
match self {
Value::Cons(pair) => Some(pair),
_ => None,
}
}
pub fn as_pair(&self) -> Option<(&Value, &Value)> {
self.as_cons().map(Cons::as_pair)
}
pub fn is_vector(&self) -> bool {
match self {
Value::Vector(_) => true,
_ => false,
}
}
pub fn as_slice(&self) -> Option<&[Value]> {
match self {
Value::Vector(elements) => Some(elements),
_ => None,
}
}
pub fn as_slice_mut(&mut self) -> Option<&mut [Value]> {
match self {
Value::Vector(elements) => Some(elements),
_ => None,
}
}
pub fn list_iter(&self) -> Option<cons::ListIter<'_>> {
match self {
Value::Cons(cell) => Some(cons::ListIter::cons(cell)),
Value::Null => Some(cons::ListIter::empty()),
_ => None,
}
}
pub fn to_vec(&self) -> Option<Vec<Value>> {
match self {
Value::Null => Some(Vec::new()),
Value::Cons(pair) => {
let (vec, rest) = pair.to_ref_vec();
if rest.is_null() {
Some(vec.into_iter().cloned().collect())
} else {
None
}
}
_ => None,
}
}
pub fn to_ref_vec(&self) -> Option<Vec<&Value>> {
match self {
Value::Null => Some(Vec::new()),
Value::Cons(pair) => {
let (vec, rest) = pair.to_ref_vec();
if rest.is_null() {
Some(vec)
} else {
None
}
}
_ => None,
}
}
pub fn get<I: Index>(&self, index: I) -> Option<&Value> {
index.index_into(self)
}
}
struct WriterFormatter<'a, 'b> {
inner: &'a mut fmt::Formatter<'b>,
}
impl<'a, 'b> io::Write for WriterFormatter<'a, 'b> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
fn io_error<E>(_: E) -> io::Error {
io::Error::new(io::ErrorKind::Other, "fmt error")
}
let s = str::from_utf8(buf).map_err(io_error)?;
self.inner.write_str(s).map_err(io_error)?;
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut wr = WriterFormatter { inner: f };
crate::print::to_writer(&mut wr, self).map_err(|_| fmt::Error)
}
}
impl str::FromStr for Value {
type Err = crate::parse::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
crate::parse::from_str(s)
}
}
mod from;
mod index;
mod partial_eq;
#[cfg(test)]
mod tests;