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"
dependencies = [
"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]]

View File

@ -23,7 +23,7 @@ dunce = "1.0.0"
indexmap = { version = "1.0.2", features = ["serde-1"] }
chrono-humanize = "0.0.11"
byte-unit = "2.1.0"
ordered-float = "1.0.2"
ordered-float = {version = "1.0.2", features = ["serde"]}
prettyprint = "0.7.0"
futures-preview = { version = "0.3.0-alpha.16", features = ["compat", "io-compat"] }
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("trim", trim::trim),
command("to-array", to_array::to_array),
command("to-ini", to_ini::to_ini),
command("to-json", to_json::to_json),
command("to-toml", to_toml::to_toml),
command("sort-by", sort_by::sort_by),

View File

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

View File

@ -62,31 +62,31 @@ pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut mem_idx = indexmap::IndexMap::new();
mem_idx.insert(
"total".to_string(),
Value::Primitive(Primitive::Bytes(x.total as u128 * 1024)),
Value::Primitive(Primitive::Bytes(x.total as u64 * 1024)),
);
mem_idx.insert(
"free".to_string(),
Value::Primitive(Primitive::Bytes(x.free as u128 * 1024)),
Value::Primitive(Primitive::Bytes(x.free as u64 * 1024)),
);
mem_idx.insert(
"avail".to_string(),
Value::Primitive(Primitive::Bytes(x.avail as u128 * 1024)),
Value::Primitive(Primitive::Bytes(x.avail as u64 * 1024)),
);
mem_idx.insert(
"buffers".to_string(),
Value::Primitive(Primitive::Bytes(x.buffers as u128 * 1024)),
Value::Primitive(Primitive::Bytes(x.buffers as u64 * 1024)),
);
mem_idx.insert(
"cached".to_string(),
Value::Primitive(Primitive::Bytes(x.cached as u128 * 1024)),
Value::Primitive(Primitive::Bytes(x.cached as u64 * 1024)),
);
mem_idx.insert(
"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(
"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)));
@ -151,10 +151,7 @@ pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> {
"temp".to_string(),
Value::float(component.get_temperature() as f64),
);
component_idx.insert(
"max".to_string(),
Value::float(component.get_max() as f64),
);
component_idx.insert("max".to_string(), Value::float(component.get_max() as f64));
if let Some(critical) = component.get_critical() {
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(),
Value::bytes(disk.get_available_space()),
);
disk_idx.insert(
"total".to_string(),
Value::bytes(disk.get_total_space()),
);
disk_idx.insert("total".to_string(), Value::bytes(disk.get_total_space()));
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();
network_idx.insert("incoming".to_string(), Value::bytes(incoming));
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());

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::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> {
let out = args.input;
let span = args.name_span;
Ok(out
.map(move |a| match serde_json::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 JSON string",
"can not convert piped data to JSON string",
span,
)))),
})
.map(
move |a| match serde_json::to_string(&value_to_json_value(&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 JSON string",
"can not convert piped data to JSON string",
span,
))))
}
},
)
.boxed())
}

View File

@ -1,11 +1,38 @@
use crate::object::{Primitive, Value};
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> {
let out = args.input;
let span = args.name_span;
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))),
Err(_) => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
"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::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 {
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 {
Nothing,
Int(i64),
#[allow(unused)]
Float(OF64),
Bytes(u128),
Bytes(u64),
String(String),
Boolean(bool),
Date(DateTime<Utc>),
@ -44,6 +44,7 @@ pub enum Primitive {
EndOfStream,
}
/*
impl Serialize for Primitive {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@ -61,6 +62,7 @@ impl Serialize for Primitive {
}
}
}
*/
impl Primitive {
crate fn type_name(&self) -> String {
@ -99,7 +101,7 @@ impl Primitive {
Primitive::Nothing => format!("{}", Color::Black.bold().paint("-")),
Primitive::EndOfStream => format!("{}", Color::Black.bold().paint("-")),
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 {
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 {
Primitive(Primitive),
Object(crate::object::Dictionary),
@ -404,7 +406,7 @@ impl Value {
crate fn as_i64(&self) -> Result<i64, ShellError> {
match self {
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
other => Err(ShellError::string(format!(
"Expected integer, got {:?}",
@ -435,7 +437,7 @@ impl Value {
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()))
}
@ -529,20 +531,18 @@ crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
_ => false,
},
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))) => {
i > (*i2 as u128)
i > (*i2 as u64)
}
(Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
i <= (*i2 as u128)
i <= (*i2 as u64)
}
(Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
i >= (*i2 as u128)
}
(Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == (*i2 as u128),
(Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => {
i != (*i2 as u128)
i >= (*i2 as u64)
}
(Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == (*i2 as u64),
(Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != (*i2 as u64),
_ => false,
},
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()),
);
dict.add("size", Value::bytes(metadata.len() as u128));
dict.add("size", Value::bytes(metadata.len() as u64));
match metadata.created() {
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 {
fn deserialize<D>(deserializer: D) -> Result<OF64, D::Error>
where
@ -32,7 +33,9 @@ impl<'de> Deserialize<'de> for OF64 {
deserializer.deserialize_f64(OF64Visitor)
}
}
*/
/*
impl Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@ -48,7 +51,7 @@ impl Serialize for Value {
}
}
}
*/
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
@ -102,6 +105,7 @@ impl<'de> Visitor<'de> for ValueVisitor {
}
}
/*
impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Value, D::Error>
where
@ -110,3 +114,4 @@ impl<'de> Deserialize<'de> for Value {
deserializer.deserialize_any(ValueVisitor)
}
}
*/

View File

@ -68,28 +68,31 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
Value::Primitive(Primitive::Bytes(b)) => {
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(
ShellError::string("Unrecognized type in stream"),
ShellError::string(format!("Unrecognized type in stream: {:?}", x)),
)))]);
}
},
Ok(NuCommand::quit) => {
break;
}
Err(_) => {
Err(e) => {
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(_) => {
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)) => {
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(