Add rusty-value serialization support for nu values

pull/3/head
trivernis 2 years ago
parent 7c2545d593
commit 06f64abb18
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -11,4 +11,5 @@ nu-engine = "0.69.1"
nu-parser = "0.69.1"
nu-protocol = "0.69.1"
paste = "1.0.9"
rusty-value = { version = "0.2.0", features = ["derive"] }
thiserror = "1.0.37"

@ -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;

@ -9,10 +9,7 @@ mod bindings;
mod command_group_config;
pub use command_group_config::CommandGroupConfig;
use crate::{
error::CrateResult,
utils::{IntoValue, SpanEmpty},
};
use crate::{error::CrateResult, into_value::IntoValue, utils::SpanEmpty};
/// Builder to create a new nu engine state
pub struct StateBuilder {

@ -1,6 +1,4 @@
use std::collections::HashMap;
use nu_protocol::{Span, Value};
use nu_protocol::Span;
pub trait SpanEmpty {
fn empty() -> Self;
@ -11,85 +9,3 @@ impl SpanEmpty for Span {
Span::new(0, 0)
}
}
pub trait IntoValue {
fn into_value(self) -> Value;
}
impl IntoValue for Value {
fn into_value(self) -> Value {
self
}
}
impl IntoValue for String {
fn into_value(self) -> Value {
Value::String {
val: self,
span: Span::empty(),
}
}
}
impl IntoValue for i64 {
fn into_value(self) -> Value {
Value::Int {
val: self,
span: Span::empty(),
}
}
}
impl IntoValue for bool {
fn into_value(self) -> Value {
Value::Bool {
val: self,
span: Span::empty(),
}
}
}
impl IntoValue for f64 {
fn into_value(self) -> Value {
Value::Float {
val: self,
span: Span::empty(),
}
}
}
impl IntoValue for char {
fn into_value(self) -> Value {
Value::String {
val: self.to_string(),
span: Span::empty(),
}
}
}
impl<'a> IntoValue for &'a str {
fn into_value(self) -> Value {
self.to_string().into_value()
}
}
impl IntoValue for HashMap<String, Value> {
fn into_value(self) -> Value {
let (cols, vals) = self.into_iter().unzip();
Value::Record {
cols,
vals,
span: Span::empty(),
}
}
}
impl IntoValue for Vec<Value> {
fn into_value(self) -> Value {
Value::List {
vals: self,
span: Span::empty(),
}
}
}

@ -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…
Cancel
Save