Make serialization full-fidelity

This commit is contained in:
Jonathan Turner 2019-06-30 18:46:49 +12:00
parent 5cac3d1135
commit c3697c67ca
13 changed files with 120 additions and 69 deletions

1
Cargo.lock generated
View File

@ -1623,6 +1623,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]

View File

@ -23,7 +23,7 @@ dunce = "1.0.0"
indexmap = { version = "1.0.2", features = ["serde-1"] } indexmap = { version = "1.0.2", features = ["serde-1"] }
chrono-humanize = "0.0.11" chrono-humanize = "0.0.11"
byte-unit = "2.1.0" byte-unit = "2.1.0"
ordered-float = "1.0.2" ordered-float = {version = "1.0.2", features = ["serde"]}
prettyprint = "0.7.0" prettyprint = "0.7.0"
futures-preview = { version = "0.3.0-alpha.16", features = ["compat", "io-compat"] } futures-preview = { version = "0.3.0-alpha.16", features = ["compat", "io-compat"] }
futures-sink-preview = "0.3.0-alpha.16" futures-sink-preview = "0.3.0-alpha.16"

View File

@ -72,7 +72,6 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
command("reject", reject::reject), command("reject", reject::reject),
command("trim", trim::trim), command("trim", trim::trim),
command("to-array", to_array::to_array), command("to-array", to_array::to_array),
command("to-ini", to_ini::to_ini),
command("to-json", to_json::to_json), command("to-json", to_json::to_json),
command("to-toml", to_toml::to_toml), command("to-toml", to_toml::to_toml),
command("sort-by", sort_by::sort_by), command("sort-by", sort_by::sort_by),

View File

@ -31,7 +31,6 @@ crate mod split_row;
crate mod sysinfo; crate mod sysinfo;
crate mod table; crate mod table;
crate mod to_array; crate mod to_array;
crate mod to_ini;
crate mod to_json; crate mod to_json;
crate mod to_toml; crate mod to_toml;
crate mod tree; crate mod tree;

View File

@ -62,31 +62,31 @@ pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut mem_idx = indexmap::IndexMap::new(); let mut mem_idx = indexmap::IndexMap::new();
mem_idx.insert( mem_idx.insert(
"total".to_string(), "total".to_string(),
Value::Primitive(Primitive::Bytes(x.total as u128 * 1024)), Value::Primitive(Primitive::Bytes(x.total as u64 * 1024)),
); );
mem_idx.insert( mem_idx.insert(
"free".to_string(), "free".to_string(),
Value::Primitive(Primitive::Bytes(x.free as u128 * 1024)), Value::Primitive(Primitive::Bytes(x.free as u64 * 1024)),
); );
mem_idx.insert( mem_idx.insert(
"avail".to_string(), "avail".to_string(),
Value::Primitive(Primitive::Bytes(x.avail as u128 * 1024)), Value::Primitive(Primitive::Bytes(x.avail as u64 * 1024)),
); );
mem_idx.insert( mem_idx.insert(
"buffers".to_string(), "buffers".to_string(),
Value::Primitive(Primitive::Bytes(x.buffers as u128 * 1024)), Value::Primitive(Primitive::Bytes(x.buffers as u64 * 1024)),
); );
mem_idx.insert( mem_idx.insert(
"cached".to_string(), "cached".to_string(),
Value::Primitive(Primitive::Bytes(x.cached as u128 * 1024)), Value::Primitive(Primitive::Bytes(x.cached as u64 * 1024)),
); );
mem_idx.insert( mem_idx.insert(
"swap total".to_string(), "swap total".to_string(),
Value::Primitive(Primitive::Bytes(x.swap_total as u128 * 1024)), Value::Primitive(Primitive::Bytes(x.swap_total as u64 * 1024)),
); );
mem_idx.insert( mem_idx.insert(
"swap free".to_string(), "swap free".to_string(),
Value::Primitive(Primitive::Bytes(x.swap_free as u128 * 1024)), Value::Primitive(Primitive::Bytes(x.swap_free as u64 * 1024)),
); );
idx.insert("mem".to_string(), Value::Object(Dictionary::from(mem_idx))); idx.insert("mem".to_string(), Value::Object(Dictionary::from(mem_idx)));
@ -151,10 +151,7 @@ pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> {
"temp".to_string(), "temp".to_string(),
Value::float(component.get_temperature() as f64), Value::float(component.get_temperature() as f64),
); );
component_idx.insert( component_idx.insert("max".to_string(), Value::float(component.get_max() as f64));
"max".to_string(),
Value::float(component.get_max() as f64),
);
if let Some(critical) = component.get_critical() { if let Some(critical) = component.get_critical() {
component_idx.insert("critical".to_string(), Value::float(critical as f64)); component_idx.insert("critical".to_string(), Value::float(critical as f64));
} }
@ -177,10 +174,7 @@ pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> {
"available".to_string(), "available".to_string(),
Value::bytes(disk.get_available_space()), Value::bytes(disk.get_available_space()),
); );
disk_idx.insert( disk_idx.insert("total".to_string(), Value::bytes(disk.get_total_space()));
"total".to_string(),
Value::bytes(disk.get_total_space()),
);
v.push(Value::Object(Dictionary::from(disk_idx))); v.push(Value::Object(Dictionary::from(disk_idx)));
} }
@ -194,7 +188,10 @@ pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut network_idx = indexmap::IndexMap::new(); let mut network_idx = indexmap::IndexMap::new();
network_idx.insert("incoming".to_string(), Value::bytes(incoming)); network_idx.insert("incoming".to_string(), Value::bytes(incoming));
network_idx.insert("outgoing".to_string(), Value::bytes(outgoing)); network_idx.insert("outgoing".to_string(), Value::bytes(outgoing));
idx.insert("network".to_string(), Value::Object(Dictionary::from(network_idx))); idx.insert(
"network".to_string(),
Value::Object(Dictionary::from(network_idx)),
);
// println!("{:#?}", system.get_network()); // println!("{:#?}", system.get_network());

View File

@ -1,17 +0,0 @@
use crate::object::{Primitive, Value};
use crate::prelude::*;
pub fn to_ini(args: CommandArgs) -> Result<OutputStream, ShellError> {
let out = args.input;
let span = args.name_span;
Ok(out
.map(move |a| match serde_ini::to_string(&a) {
Ok(x) => ReturnValue::Value(Value::Primitive(Primitive::String(x))),
Err(_) => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
"Can not convert to INI string",
"can not convert piped data to INI string",
span,
)))),
})
.boxed())
}

View File

@ -1,17 +1,54 @@
use crate::object::{Primitive, Value}; use crate::object::{Primitive, Value};
use crate::prelude::*; use crate::prelude::*;
pub fn value_to_json_value(v: &Value) -> serde_json::Value {
match v {
Value::Primitive(Primitive::Boolean(b)) => serde_json::Value::Bool(*b),
Value::Primitive(Primitive::Bytes(b)) => {
serde_json::Value::Number(serde_json::Number::from(*b as u64))
}
Value::Primitive(Primitive::Date(d)) => serde_json::Value::String(d.to_string()),
Value::Primitive(Primitive::EndOfStream) => serde_json::Value::Null,
Value::Primitive(Primitive::Float(f)) => {
serde_json::Value::Number(serde_json::Number::from_f64(f.into_inner()).unwrap())
}
Value::Primitive(Primitive::Int(i)) => {
serde_json::Value::Number(serde_json::Number::from(*i))
}
Value::Primitive(Primitive::Nothing) => serde_json::Value::Null,
Value::Primitive(Primitive::String(s)) => serde_json::Value::String(s.clone()),
Value::Filesystem => serde_json::Value::Null,
Value::List(l) => {
serde_json::Value::Array(l.iter().map(|x| value_to_json_value(x)).collect())
}
Value::Error(e) => serde_json::Value::String(e.to_string()),
Value::Block(_) => serde_json::Value::Null,
Value::Object(o) => {
let mut m = serde_json::Map::new();
for (k, v) in o.entries.iter() {
m.insert(k.name.display().to_string(), value_to_json_value(v));
}
serde_json::Value::Object(m)
}
}
}
pub fn to_json(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn to_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
let out = args.input; let out = args.input;
let span = args.name_span; let span = args.name_span;
Ok(out Ok(out
.map(move |a| match serde_json::to_string(&a) { .map(
move |a| match serde_json::to_string(&value_to_json_value(&a)) {
Ok(x) => ReturnValue::Value(Value::Primitive(Primitive::String(x))), Ok(x) => ReturnValue::Value(Value::Primitive(Primitive::String(x))),
Err(_) => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( Err(_) => {
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
"Can not convert to JSON string", "Can not convert to JSON string",
"can not convert piped data to JSON string", "can not convert piped data to JSON string",
span, span,
)))), ))))
}) }
},
)
.boxed()) .boxed())
} }

View File

@ -1,11 +1,38 @@
use crate::object::{Primitive, Value}; use crate::object::{Primitive, Value};
use crate::prelude::*; use crate::prelude::*;
pub fn value_to_toml_value(v: &Value) -> toml::Value {
match v {
Value::Primitive(Primitive::Boolean(b)) => toml::Value::Boolean(*b),
Value::Primitive(Primitive::Bytes(b)) => toml::Value::Integer(*b as i64),
Value::Primitive(Primitive::Date(d)) => toml::Value::String(d.to_string()),
Value::Primitive(Primitive::EndOfStream) => {
toml::Value::String("<End of Stream>".to_string())
}
Value::Primitive(Primitive::Float(f)) => toml::Value::Float(f.into_inner()),
Value::Primitive(Primitive::Int(i)) => toml::Value::Integer(*i),
Value::Primitive(Primitive::Nothing) => toml::Value::String("<Nothing>".to_string()),
Value::Primitive(Primitive::String(s)) => toml::Value::String(s.clone()),
Value::Filesystem => toml::Value::String("<Filesystem>".to_string()),
Value::List(l) => toml::Value::Array(l.iter().map(|x| value_to_toml_value(x)).collect()),
Value::Error(e) => toml::Value::String(e.to_string()),
Value::Block(_) => toml::Value::String("<Block>".to_string()),
Value::Object(o) => {
let mut m = toml::map::Map::new();
for (k, v) in o.entries.iter() {
m.insert(k.name.display().to_string(), value_to_toml_value(v));
}
toml::Value::Table(m)
}
}
}
pub fn to_toml(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn to_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
let out = args.input; let out = args.input;
let span = args.name_span; let span = args.name_span;
Ok(out Ok(out
.map(move |a| match toml::to_string(&a) { .map(move |a| match toml::to_string(&value_to_toml_value(&a)) {
Ok(x) => ReturnValue::Value(Value::Primitive(Primitive::String(x))), Ok(x) => ReturnValue::Value(Value::Primitive(Primitive::String(x))),
Err(_) => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( Err(_) => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
"Can not convert to TOML string", "Can not convert to TOML string",

View File

@ -13,7 +13,7 @@ use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer}
use std::fmt; use std::fmt;
use std::time::SystemTime; use std::time::SystemTime;
#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, new)] #[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, new, Serialize, Deserialize)]
pub struct OF64 { pub struct OF64 {
crate inner: OrderedFloat<f64>, crate inner: OrderedFloat<f64>,
} }
@ -30,13 +30,13 @@ impl From<f64> for OF64 {
} }
} }
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Deserialize)] #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Deserialize, Serialize)]
pub enum Primitive { pub enum Primitive {
Nothing, Nothing,
Int(i64), Int(i64),
#[allow(unused)] #[allow(unused)]
Float(OF64), Float(OF64),
Bytes(u128), Bytes(u64),
String(String), String(String),
Boolean(bool), Boolean(bool),
Date(DateTime<Utc>), Date(DateTime<Utc>),
@ -44,6 +44,7 @@ pub enum Primitive {
EndOfStream, EndOfStream,
} }
/*
impl Serialize for Primitive { impl Serialize for Primitive {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@ -61,6 +62,7 @@ impl Serialize for Primitive {
} }
} }
} }
*/
impl Primitive { impl Primitive {
crate fn type_name(&self) -> String { crate fn type_name(&self) -> String {
@ -99,7 +101,7 @@ impl Primitive {
Primitive::Nothing => format!("{}", Color::Black.bold().paint("-")), Primitive::Nothing => format!("{}", Color::Black.bold().paint("-")),
Primitive::EndOfStream => format!("{}", Color::Black.bold().paint("-")), Primitive::EndOfStream => format!("{}", Color::Black.bold().paint("-")),
Primitive::Bytes(b) => { Primitive::Bytes(b) => {
let byte = byte_unit::Byte::from_bytes(*b); let byte = byte_unit::Byte::from_bytes(*b as u128);
if byte.get_bytes() == 0u128 { if byte.get_bytes() == 0u128 {
return Color::Black.bold().paint("Empty".to_string()).to_string(); return Color::Black.bold().paint("Empty".to_string()).to_string();
@ -194,7 +196,7 @@ impl Block {
} }
} }
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone)] #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Serialize, Deserialize)]
pub enum Value { pub enum Value {
Primitive(Primitive), Primitive(Primitive),
Object(crate::object::Dictionary), Object(crate::object::Dictionary),
@ -404,7 +406,7 @@ impl Value {
crate fn as_i64(&self) -> Result<i64, ShellError> { crate fn as_i64(&self) -> Result<i64, ShellError> {
match self { match self {
Value::Primitive(Primitive::Int(i)) => Ok(*i), Value::Primitive(Primitive::Int(i)) => Ok(*i),
Value::Primitive(Primitive::Bytes(b)) if *b <= std::i64::MAX as u128 => Ok(*b as i64), Value::Primitive(Primitive::Bytes(b)) => Ok(*b as i64),
// TODO: this should definitely be more general with better errors // TODO: this should definitely be more general with better errors
other => Err(ShellError::string(format!( other => Err(ShellError::string(format!(
"Expected integer, got {:?}", "Expected integer, got {:?}",
@ -435,7 +437,7 @@ impl Value {
Value::Primitive(Primitive::String(s.into())) Value::Primitive(Primitive::String(s.into()))
} }
pub fn bytes(s: impl Into<u128>) -> Value { pub fn bytes(s: impl Into<u64>) -> Value {
Value::Primitive(Primitive::Bytes(s.into())) Value::Primitive(Primitive::Bytes(s.into()))
} }
@ -529,20 +531,18 @@ crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
_ => false, _ => false,
}, },
Value::Primitive(Primitive::Bytes(i)) => match (op, rhs) { Value::Primitive(Primitive::Bytes(i)) => match (op, rhs) {
(Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < (*i2 as u128), (Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < (*i2 as u64),
(Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => { (Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => {
i > (*i2 as u128) i > (*i2 as u64)
} }
(Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => { (Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
i <= (*i2 as u128) i <= (*i2 as u64)
} }
(Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => { (Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
i >= (*i2 as u128) i >= (*i2 as u64)
}
(Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == (*i2 as u128),
(Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => {
i != (*i2 as u128)
} }
(Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == (*i2 as u64),
(Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != (*i2 as u64),
_ => false, _ => false,
}, },
Value::Primitive(Primitive::Int(i)) => match (op, rhs) { Value::Primitive(Primitive::Int(i)) => match (op, rhs) {

View File

@ -29,7 +29,7 @@ crate fn dir_entry_dict(entry: &std::fs::DirEntry) -> Result<Dictionary, ShellEr
Value::boolean(metadata.permissions().readonly()), Value::boolean(metadata.permissions().readonly()),
); );
dict.add("size", Value::bytes(metadata.len() as u128)); dict.add("size", Value::bytes(metadata.len() as u64));
match metadata.created() { match metadata.created() {
Ok(c) => dict.add("created", Value::system_date(c)), Ok(c) => dict.add("created", Value::system_date(c)),

View File

@ -24,6 +24,7 @@ impl Visitor<'_> for OF64Visitor {
} }
} }
/*
impl<'de> Deserialize<'de> for OF64 { impl<'de> Deserialize<'de> for OF64 {
fn deserialize<D>(deserializer: D) -> Result<OF64, D::Error> fn deserialize<D>(deserializer: D) -> Result<OF64, D::Error>
where where
@ -32,7 +33,9 @@ impl<'de> Deserialize<'de> for OF64 {
deserializer.deserialize_f64(OF64Visitor) deserializer.deserialize_f64(OF64Visitor)
} }
} }
*/
/*
impl Serialize for Value { impl Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@ -48,7 +51,7 @@ impl Serialize for Value {
} }
} }
} }
*/
struct ValueVisitor; struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor { impl<'de> Visitor<'de> for ValueVisitor {
@ -102,6 +105,7 @@ impl<'de> Visitor<'de> for ValueVisitor {
} }
} }
/*
impl<'de> Deserialize<'de> for Value { impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Value, D::Error> fn deserialize<D>(deserializer: D) -> Result<Value, D::Error>
where where
@ -110,3 +114,4 @@ impl<'de> Deserialize<'de> for Value {
deserializer.deserialize_any(ValueVisitor) deserializer.deserialize_any(ValueVisitor)
} }
} }
*/

View File

@ -68,28 +68,31 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
Value::Primitive(Primitive::Bytes(b)) => { Value::Primitive(Primitive::Bytes(b)) => {
send_response(vec![ReturnValue::Value(Value::bytes( send_response(vec![ReturnValue::Value(Value::bytes(
b + inc_by as u128, b + inc_by as u64,
))]); ))]);
} }
_ => { x => {
send_response(vec![ReturnValue::Value(Value::Error(Box::new( send_response(vec![ReturnValue::Value(Value::Error(Box::new(
ShellError::string("Unrecognized type in stream"), ShellError::string(format!("Unrecognized type in stream: {:?}", x)),
)))]); )))]);
} }
}, },
Ok(NuCommand::quit) => { Ok(NuCommand::quit) => {
break; break;
} }
Err(_) => { Err(e) => {
send_response(vec![ReturnValue::Value(Value::Error(Box::new( send_response(vec![ReturnValue::Value(Value::Error(Box::new(
ShellError::string("Unrecognized type in stream"), ShellError::string(format!(
"Unrecognized type in stream: {} {:?}",
input, e
)),
)))]); )))]);
} }
} }
} }
Err(_) => { Err(_) => {
send_response(vec![ReturnValue::Value(Value::Error(Box::new( send_response(vec![ReturnValue::Value(Value::Error(Box::new(
ShellError::string("Unrecognized type in stream"), ShellError::string(format!("Unrecognized type in stream: {}", input)),
)))]); )))]);
} }
} }

View File

@ -53,7 +53,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
Value::Primitive(Primitive::Bytes(b)) => { Value::Primitive(Primitive::Bytes(b)) => {
total += b as i64; total += b as i64;
send_response(vec![ReturnValue::Value(Value::bytes(total as u128))]); send_response(vec![ReturnValue::Value(Value::bytes(total as u64))]);
} }
_ => { _ => {
send_response(vec![ReturnValue::Value(Value::Error(Box::new( send_response(vec![ReturnValue::Value(Value::Error(Box::new(