Merge pull request #145 from jonathandturner/serial

Full-fidelity ser/de
This commit is contained in:
Jonathan Turner 2019-06-30 19:04:52 +12:00 committed by GitHub
commit ea18583e30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 112 additions and 199 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

@ -4,7 +4,6 @@ crate mod desc;
crate mod dict;
crate mod files;
crate mod process;
crate mod serialization;
crate mod types;
crate use base::{Primitive, Value};

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,24 +44,6 @@ pub enum Primitive {
EndOfStream,
}
impl Serialize for Primitive {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Primitive::Nothing => serializer.serialize_i32(0),
Primitive::EndOfStream => serializer.serialize_i32(0),
Primitive::Int(i) => serializer.serialize_i64(*i),
Primitive::Float(OF64 { inner: f }) => serializer.serialize_f64(f.into_inner()),
Primitive::Bytes(b) => serializer.serialize_u128(*b),
Primitive::String(ref s) => serializer.serialize_str(s),
Primitive::Boolean(b) => serializer.serialize_bool(*b),
Primitive::Date(d) => serializer.serialize_str(&d.to_string()),
}
}
}
impl Primitive {
crate fn type_name(&self) -> String {
use Primitive::*;
@ -99,7 +81,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 +176,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 +386,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 +417,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 +511,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

@ -1,112 +0,0 @@
use crate::object::base::OF64;
use crate::prelude::*;
use ordered_float::OrderedFloat;
use serde::de::{self, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
struct OF64Visitor;
impl Visitor<'_> for OF64Visitor {
type Value = OF64;
fn visit_f64<E>(self, value: f64) -> Result<OF64, E> {
Ok(OF64::new(OrderedFloat(value)))
}
fn visit_f32<E>(self, value: f32) -> Result<OF64, E> {
Ok(OF64::new(OrderedFloat(value as f64)))
}
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a float")
}
}
impl<'de> Deserialize<'de> for OF64 {
fn deserialize<D>(deserializer: D) -> Result<OF64, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_f64(OF64Visitor)
}
}
impl Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Value::Primitive(p) => p.serialize(serializer),
Value::Object(o) => o.serialize(serializer),
Value::List(l) => l.serialize(serializer),
Value::Block(b) => b.serialize(serializer),
Value::Error(e) => e.serialize(serializer),
Value::Filesystem => "".serialize(serializer),
}
}
}
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
type Value = Value;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a shell value")
}
fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::int(value))
}
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::int(value))
}
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::int(value))
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
// TODO: Handle overflow better
Ok(Value::int(value as i64))
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::string(value))
}
fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::boolean(value))
}
}
impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Value, D::Error>
where
D: Deserializer<'de>,
{
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(