Add rusty-value serialization support for nu values
parent
7c2545d593
commit
06f64abb18
@ -0,0 +1,196 @@
|
||||
use nu_protocol::{Span, Value};
|
||||
use rusty_value::{Fields, HashableValue, RustyValue};
|
||||
|
||||
use crate::utils::SpanEmpty;
|
||||
|
||||
pub struct RawValue(Value);
|
||||
|
||||
/// Converts the given type into a value
|
||||
/// This trait is implemented for all types that
|
||||
/// Implement the RustyValue trait
|
||||
pub trait IntoValue {
|
||||
fn into_value(self) -> Value;
|
||||
}
|
||||
|
||||
impl IntoValue for RawValue {
|
||||
fn into_value(self) -> Value {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait to avoid conflicts
|
||||
pub(crate) trait RustyIntoValue {
|
||||
fn into_value(self) -> Value;
|
||||
}
|
||||
|
||||
pub(crate) trait HashableIntoString {
|
||||
fn into_string(self) -> String;
|
||||
}
|
||||
|
||||
impl HashableIntoString for HashableValue {
|
||||
fn into_string(self) -> String {
|
||||
match self {
|
||||
HashableValue::Primitive(p) => p.to_string(),
|
||||
HashableValue::List(l) => l
|
||||
.into_iter()
|
||||
.map(|v| v.into_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(","),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RustyIntoValue for Vec<Value> {
|
||||
fn into_value(self) -> Value {
|
||||
Value::List {
|
||||
vals: self,
|
||||
span: Span::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RustyIntoValue for rusty_value::Value {
|
||||
fn into_value(self) -> Value {
|
||||
match self {
|
||||
rusty_value::Value::Primitive(p) => p.into_value(),
|
||||
rusty_value::Value::Struct(s) => {
|
||||
if let Fields::Unit = &s.fields {
|
||||
Value::String {
|
||||
val: s.name,
|
||||
span: Span::empty(),
|
||||
}
|
||||
} else {
|
||||
s.fields.into_value()
|
||||
}
|
||||
}
|
||||
rusty_value::Value::Enum(e) => {
|
||||
if let Fields::Unit = &e.fields {
|
||||
Value::String {
|
||||
val: e.variant,
|
||||
span: Span::empty(),
|
||||
}
|
||||
} else {
|
||||
e.fields.into_value()
|
||||
}
|
||||
}
|
||||
rusty_value::Value::Map(map) => {
|
||||
let mut cols = Vec::new();
|
||||
let mut vals = Vec::new();
|
||||
|
||||
for (key, val) in map {
|
||||
cols.push(key.into_string());
|
||||
vals.push(val.into_value());
|
||||
}
|
||||
Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: Span::empty(),
|
||||
}
|
||||
}
|
||||
rusty_value::Value::List(l) => {
|
||||
let vals = l.into_iter().map(|e| e.into_value()).collect();
|
||||
|
||||
Value::List {
|
||||
vals,
|
||||
span: Span::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RustyIntoValue for rusty_value::Primitive {
|
||||
fn into_value(self) -> Value {
|
||||
match self {
|
||||
rusty_value::Primitive::Integer(i) => i.into_value(),
|
||||
rusty_value::Primitive::Float(f) => f.into_value(),
|
||||
rusty_value::Primitive::String(val) => Value::String {
|
||||
val,
|
||||
span: Span::empty(),
|
||||
},
|
||||
rusty_value::Primitive::Char(val) => Value::String {
|
||||
val: val.to_string(),
|
||||
span: Span::empty(),
|
||||
},
|
||||
rusty_value::Primitive::Bool(val) => Value::Bool {
|
||||
val,
|
||||
span: Span::empty(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RustyIntoValue for rusty_value::Fields {
|
||||
fn into_value(self) -> Value {
|
||||
match self {
|
||||
rusty_value::Fields::Named(named) => {
|
||||
let mut cols = Vec::with_capacity(named.len());
|
||||
let mut vals = Vec::with_capacity(named.len());
|
||||
|
||||
for (k, v) in named {
|
||||
cols.push(k);
|
||||
vals.push(v.into_value());
|
||||
}
|
||||
Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: Span::empty(),
|
||||
}
|
||||
}
|
||||
rusty_value::Fields::Unnamed(unnamed) => {
|
||||
let vals = unnamed.into_iter().map(|v| v.into_value()).collect();
|
||||
|
||||
Value::List {
|
||||
vals,
|
||||
span: Span::empty(),
|
||||
}
|
||||
}
|
||||
rusty_value::Fields::Unit => Value::Nothing {
|
||||
span: Span::empty(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RustyIntoValue for rusty_value::Integer {
|
||||
fn into_value(self) -> Value {
|
||||
let val = match self {
|
||||
rusty_value::Integer::USize(i) => i as i64,
|
||||
rusty_value::Integer::ISize(i) => i as i64,
|
||||
rusty_value::Integer::U8(i) => i as i64,
|
||||
rusty_value::Integer::I8(i) => i as i64,
|
||||
rusty_value::Integer::U16(i) => i as i64,
|
||||
rusty_value::Integer::I16(i) => i as i64,
|
||||
rusty_value::Integer::U32(i) => i as i64,
|
||||
rusty_value::Integer::I32(i) => i as i64,
|
||||
rusty_value::Integer::U64(i) => i as i64,
|
||||
rusty_value::Integer::I64(i) => i,
|
||||
rusty_value::Integer::U128(i) => i as i64,
|
||||
rusty_value::Integer::I128(i) => i as i64,
|
||||
};
|
||||
Value::Int {
|
||||
val,
|
||||
span: Span::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RustyIntoValue for rusty_value::Float {
|
||||
#[inline]
|
||||
fn into_value(self) -> Value {
|
||||
let val = match self {
|
||||
rusty_value::Float::F32(f) => f as f64,
|
||||
rusty_value::Float::F64(f) => f,
|
||||
};
|
||||
Value::Float {
|
||||
val,
|
||||
span: Span::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: RustyValue> IntoValue for R {
|
||||
fn into_value(self) -> Value {
|
||||
self.into_rusty_value().into_value()
|
||||
}
|
||||
}
|
@ -1,5 +1,9 @@
|
||||
pub(crate) mod error;
|
||||
pub(crate) mod into_value;
|
||||
pub mod state_builder;
|
||||
pub(crate) mod utils;
|
||||
|
||||
pub use into_value::*;
|
||||
pub use rusty_value;
|
||||
|
||||
pub type Error = error::CrateError;
|
||||
|
@ -0,0 +1,50 @@
|
||||
use embed_nu::IntoValue;
|
||||
use nu_protocol::Value;
|
||||
use rusty_value::RustyValue;
|
||||
use std::mem;
|
||||
|
||||
#[derive(RustyValue, Debug, Clone)]
|
||||
pub struct TestStruct {
|
||||
foo: String,
|
||||
bar: Vec<String>,
|
||||
baz: TestEnum,
|
||||
}
|
||||
|
||||
#[derive(RustyValue, Debug, Clone)]
|
||||
pub enum TestEnum {
|
||||
Empty,
|
||||
Unnamed(String),
|
||||
Named { foo: usize, bar: Box<TestStruct> },
|
||||
}
|
||||
|
||||
impl TestStruct {
|
||||
pub fn new_test() -> Self {
|
||||
Self {
|
||||
foo: "Hello".to_string(),
|
||||
bar: vec!["One".to_string(), "Two".to_string()],
|
||||
baz: TestEnum::Named {
|
||||
foo: 12,
|
||||
bar: Box::new(TestStruct {
|
||||
foo: "World".to_string(),
|
||||
bar: vec![],
|
||||
baz: TestEnum::Empty,
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_creates_values_from_structs() {
|
||||
let test_val = TestStruct::new_test();
|
||||
dbg!(mem::size_of::<TestStruct>());
|
||||
dbg!(&test_val);
|
||||
let rusty_val = test_val.clone().into_rusty_value();
|
||||
dbg!(mem::size_of::<rusty_value::Value>());
|
||||
dbg!(&rusty_val);
|
||||
let val = test_val.into_value();
|
||||
dbg!(mem::size_of::<Value>());
|
||||
dbg!(&val);
|
||||
|
||||
assert!(val.as_record().is_ok())
|
||||
}
|
Loading…
Reference in New Issue