2019-05-11 22:59:57 +00:00
|
|
|
use crate::errors::ShellError;
|
2019-05-10 16:59:12 +00:00
|
|
|
use crate::format::{EntriesView, GenericView};
|
|
|
|
use crate::object::desc::DataDescriptor;
|
|
|
|
use chrono::NaiveDateTime;
|
|
|
|
use std::fmt::Debug;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Primitive {
|
|
|
|
Nothing,
|
|
|
|
Int(i64),
|
|
|
|
Float(f64),
|
|
|
|
String(String),
|
|
|
|
Boolean(bool),
|
|
|
|
Date(NaiveDateTime),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Primitive {
|
|
|
|
crate fn format(&self) -> String {
|
|
|
|
match self {
|
|
|
|
Primitive::Nothing => format!("Nothing"),
|
|
|
|
Primitive::Int(i) => format!("{}", i),
|
|
|
|
Primitive::Float(f) => format!("{}", f),
|
|
|
|
Primitive::String(s) => format!("{:?}", s),
|
|
|
|
Primitive::Boolean(b) => format!("{:?}", b),
|
|
|
|
Primitive::Date(d) => format!("{}", d),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Value {
|
|
|
|
Primitive(Primitive),
|
|
|
|
Object(Box<dyn ShellObject>),
|
|
|
|
List(Vec<Value>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ShellObject for Value {
|
|
|
|
fn to_shell_string(&self) -> String {
|
|
|
|
match self {
|
|
|
|
Value::Primitive(p) => p.format(),
|
|
|
|
Value::Object(o) => o.to_shell_string(),
|
|
|
|
Value::List(l) => format!("[list List]"),
|
|
|
|
}
|
|
|
|
}
|
2019-05-15 16:12:38 +00:00
|
|
|
|
2019-05-10 16:59:12 +00:00
|
|
|
fn data_descriptors(&self) -> Vec<DataDescriptor> {
|
|
|
|
match self {
|
|
|
|
Value::Primitive(p) => vec![],
|
|
|
|
Value::Object(o) => o.data_descriptors(),
|
|
|
|
Value::List(l) => vec![],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_data(&'a self, desc: &DataDescriptor) -> crate::MaybeOwned<'a, Value> {
|
|
|
|
match self {
|
|
|
|
Value::Primitive(p) => crate::MaybeOwned::Owned(Value::nothing()),
|
|
|
|
Value::Object(o) => o.get_data(desc),
|
|
|
|
Value::List(l) => crate::MaybeOwned::Owned(Value::nothing()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Value {
|
|
|
|
crate fn format_leaf(&self) -> String {
|
|
|
|
match self {
|
|
|
|
Value::Primitive(p) => p.format(),
|
|
|
|
Value::Object(o) => format!("[object Object]"),
|
|
|
|
Value::List(l) => format!("[list List]"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-11 22:59:57 +00:00
|
|
|
crate fn as_string(&self) -> Result<String, ShellError> {
|
|
|
|
match self {
|
|
|
|
Value::Primitive(Primitive::String(s)) => Ok(s.to_string()),
|
|
|
|
|
|
|
|
// TODO: this should definitely be more general with better errors
|
2019-05-13 17:30:51 +00:00
|
|
|
other => Err(ShellError::string(format!(
|
|
|
|
"Expected string, got {:?}",
|
|
|
|
other
|
|
|
|
))),
|
2019-05-11 22:59:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
crate fn as_int(&self) -> Result<i64, ShellError> {
|
|
|
|
match self {
|
|
|
|
Value::Primitive(Primitive::Int(i)) => Ok(*i),
|
|
|
|
// TODO: this should definitely be more general with better errors
|
|
|
|
other => Err(ShellError::string(format!(
|
|
|
|
"Expected integer, got {:?}",
|
|
|
|
other
|
|
|
|
))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-10 16:59:12 +00:00
|
|
|
crate fn string(s: impl Into<String>) -> Value {
|
|
|
|
Value::Primitive(Primitive::String(s.into()))
|
|
|
|
}
|
|
|
|
|
|
|
|
crate fn int(s: impl Into<i64>) -> Value {
|
|
|
|
Value::Primitive(Primitive::Int(s.into()))
|
|
|
|
}
|
|
|
|
|
|
|
|
crate fn boolean(s: impl Into<bool>) -> Value {
|
|
|
|
Value::Primitive(Primitive::Boolean(s.into()))
|
|
|
|
}
|
|
|
|
|
|
|
|
crate fn nothing() -> Value {
|
|
|
|
Value::Primitive(Primitive::Nothing)
|
|
|
|
}
|
|
|
|
|
|
|
|
crate fn list(values: impl Into<Vec<Value>>) -> Value {
|
|
|
|
Value::List(values.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
crate fn object(value: impl ShellObject + 'static) -> Value {
|
|
|
|
Value::Object(Box::new(value))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait ShellObject: Debug {
|
|
|
|
fn to_shell_string(&self) -> String;
|
|
|
|
fn data_descriptors(&self) -> Vec<DataDescriptor>;
|
|
|
|
fn get_data(&'a self, desc: &DataDescriptor) -> crate::MaybeOwned<'a, Value>;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait ToEntriesView {
|
|
|
|
fn to_entries_view(&self) -> EntriesView;
|
|
|
|
}
|
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
impl<T> ToEntriesView for T
|
|
|
|
where
|
|
|
|
T: ShellObject,
|
|
|
|
{
|
2019-05-10 16:59:12 +00:00
|
|
|
fn to_entries_view(&self) -> EntriesView {
|
|
|
|
let descs = self.data_descriptors();
|
|
|
|
let mut entries = vec![];
|
|
|
|
|
|
|
|
for desc in descs {
|
|
|
|
let value = self.get_data(&desc);
|
|
|
|
|
|
|
|
let formatted_value = match value.borrow() {
|
|
|
|
Value::Primitive(p) => p.format(),
|
|
|
|
Value::Object(o) => format!("[object Object]"),
|
|
|
|
Value::List(l) => format!("[object List]"),
|
|
|
|
};
|
|
|
|
|
|
|
|
entries.push((desc.name.clone(), formatted_value))
|
|
|
|
}
|
|
|
|
|
|
|
|
EntriesView::new(entries)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
impl ShellObject for Box<dyn ShellObject> {
|
|
|
|
fn to_shell_string(&self) -> String {
|
|
|
|
(**self).to_shell_string()
|
|
|
|
}
|
|
|
|
fn data_descriptors(&self) -> Vec<DataDescriptor> {
|
|
|
|
(**self).data_descriptors()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_data(&'a self, desc: &DataDescriptor) -> crate::MaybeOwned<'a, Value> {
|
|
|
|
(**self).get_data(desc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-10 16:59:12 +00:00
|
|
|
pub trait ToGenericView {
|
|
|
|
fn to_generic_view(&self) -> GenericView;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToGenericView for Value {
|
|
|
|
fn to_generic_view(&self) -> GenericView<'_> {
|
|
|
|
GenericView::new(self)
|
|
|
|
}
|
|
|
|
}
|