You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
5.2 KiB

//! Formatting specifiers for the config file format
use super::*;
use sexp::{
Sexp,
Atom,
};
/// A valid type in the config file
#[derive(Debug)]
pub enum LispType
{
List,
String,
Integer,
Float,
/// A non-descript atom, either String, Integer, Float, or the empty list.
Atom,
}
impl From<Sexp> for LispType
{
fn from(from: Sexp) -> Self
{
match from {
Sexp::Atom(atom) => atom.into(),
Sexp::List(_) => Self::List
}
}
}
impl From<&Sexp> for LispType
{
fn from(from: &Sexp) -> Self
{
match from {
Sexp::Atom(atom) => atom.into(),
Sexp::List(_) => Self::List
}
}
}
impl From<&Atom> for LispType
{
fn from(from: &Atom) -> Self
{
match from {
Atom::F(_) => Self::Float,
Atom::I(_) => Self::Integer,
Atom::S(_) => Self::String,
}
}
}
impl From<Atom> for LispType
{
fn from(from: Atom) -> Self
{
match from {
Atom::F(_) => Self::Float,
Atom::I(_) => Self::Integer,
Atom::S(_) => Self::String,
}
}
}
impl<T> From<Result<T, Error>> for LispType
where T: Into<LispType>
{
fn from(from: Result<T, Error>) -> Self
{
match from {
Ok(value) => value.into(),
Err(Error::TypeError{got,..}) => got,
_ => unreachable!("you shouldn't use this here"),
}
}
}
impl std::fmt::Display for LispType
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
f.write_str(match self {
Self::List => "list",
Self::String => "string",
Self::Integer => "integer",
Self::Float => "float",
Self::Atom => "nil",
})
}
}
pub trait LispExt
{
/// Try to get `car` and `cdr`
fn try_split<'a>(&'a self) -> Result<(&'a Sexp, &'a [Sexp]), Error>;
}
impl LispExt for Vec<Sexp>
{
fn try_split<'a>(&'a self) -> Result<(&'a Sexp, &'a [Sexp]), Error>
{
if self.len() > 1 {
Ok((&self[0], &self[1..]))
} else if self.len() > 0{
Ok((&self[0], &[]))
} else {
Err(Error::UnexpectedEmpty)
}
}
}
// Sexp doesn't use try_from(), so...
pub trait TryIntoExt: Sized
{
fn try_into_list(self) -> Result<Vec<Sexp>, Error>;
fn try_into_atom(self) -> Result<Atom, Error>;
fn try_into_string(self) -> Result<String, Error>;
fn try_into_int(self) -> Result<i64, Error>;
fn try_into_float(self) -> Result<f64, Error>;
}
impl TryIntoExt for Sexp
{
fn try_into_list(self) -> Result<Vec<Sexp>, Error>
{
match self {
Sexp::List(this) => Ok(this),
other => Err(Error::bad_type(LispType::List, other)),
}
}
fn try_into_atom(self) -> Result<Atom, Error>
{
match self {
Sexp::Atom(this) => Ok(this),
other => Err(Error::bad_type(LispType::Atom, other)),
}
}
fn try_into_string(self) -> Result<String, Error>
{
match self.try_into_atom() {
Ok(Atom::S(this)) => Ok(this),
other => Err(Error::bad_type(LispType::String, other)),
}
}
fn try_into_int(self) -> Result<i64, Error>
{
match self.try_into_atom() {
Ok(Atom::I(this)) => Ok(this),
other => Err(Error::bad_type(LispType::Integer, other)),
}
}
fn try_into_float(self) -> Result<f64, Error>
{
match self.try_into_atom() {
Ok(Atom::F(this)) => Ok(this),
other => Err(Error::bad_type(LispType::Float, other)),
}
}
}
impl TryIntoExt for Atom
{
#[inline]
fn try_into_list(self) -> Result<Vec<Sexp>, Error>
{
Err(Error::bad_type(LispType::List, self))
}
#[inline]
fn try_into_atom(self) -> Result<Atom, Error>
{
Ok(self)
}
fn try_into_string(self) -> Result<String, Error>
{
match self {
Atom::S(this) => Ok(this),
other => Err(Error::bad_type(LispType::String, other)),
}
}
fn try_into_int(self) -> Result<i64, Error>
{
match self {
Atom::I(this) => Ok(this),
other => Err(Error::bad_type(LispType::Integer, other)),
}
}
fn try_into_float(self) -> Result<f64, Error>
{
match self {
Atom::F(this) => Ok(this),
other => Err(Error::bad_type(LispType::Float, other)),
}
}
}
// To avoid some `clone()`s
pub trait TryGetExt: Sized
{
fn try_get_list(&self) -> Result<&[Sexp], Error>;
fn try_get_atom(&self) -> Result<&Atom, Error>;
fn try_get_string(&self) -> Result<&String, Error>;
fn try_get_int(&self) -> Result<&i64, Error>;
fn try_get_float(&self) -> Result<&f64, Error>;
}
impl TryGetExt for Sexp
{
fn try_get_list(&self) -> Result<&[Sexp], Error>
{
match self {
Self::List(list) => Ok(&list[..]),
other => Err(Error::bad_type(LispType::List, other)),
}
}
fn try_get_atom(&self) -> Result<&Atom, Error>
{
match self {
Self::Atom(atom) => Ok(atom),
other => Err(Error::bad_type(LispType::Atom, other)),
}
}
fn try_get_string(&self) -> Result<&String, Error>
{
match self {
Self::Atom(Atom::S(string)) => Ok(string),
other => Err(Error::bad_type(LispType::String, other)),
}
}
fn try_get_int(&self) -> Result<&i64, Error>
{
match self {
Self::Atom(Atom::I(int)) => Ok(int),
other => Err(Error::bad_type(LispType::Integer, other)),
}
}
fn try_get_float(&self) -> Result<&f64, Error>
{
match self {
Self::Atom(Atom::F(float)) => Ok(float),
other => Err(Error::bad_type(LispType::Float, other)),
}
}
}