You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
embed-nu/src/into_value.rs

213 lines
6.4 KiB
Rust

use nu_protocol::{Record, Span, Value};
use rusty_value::{Fields, HashableValue, RustyValue};
use crate::utils::NewEmpty;
/// A helper struct to allow IntoValue operations for nu values
pub struct RawValue(pub 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 {
#[inline]
fn into_value(self) -> Value {
self.0
}
}
/// Helper trait to avoid conflicts
pub 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(","),
HashableValue::None => String::new(),
}
}
}
impl RustyIntoValue for Vec<Value> {
#[inline]
fn into_value(self) -> Value {
Value::List {
vals: self,
internal_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,
internal_span: Span::empty(),
}
} else {
s.fields.into_value()
}
}
rusty_value::Value::Enum(e) => {
if let Fields::Unit = &e.fields {
Value::String {
val: e.variant,
internal_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 {
val: Record::from_raw_cols_vals_unchecked(cols, vals),
internal_span: Span::empty(),
}
}
rusty_value::Value::List(l) => {
let vals = l.into_iter().map(|e| e.into_value()).collect();
Value::List {
vals,
internal_span: Span::empty(),
}
}
rusty_value::Value::None => Value::Nothing {
internal_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,
internal_span: Span::empty(),
},
rusty_value::Primitive::Char(val) => Value::String {
val: val.to_string(),
internal_span: Span::empty(),
},
rusty_value::Primitive::Bool(val) => Value::Bool {
val,
internal_span: Span::empty(),
},
rusty_value::Primitive::OsString(osstr) => osstr.to_string_lossy().into_value(),
}
}
}
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 {
val: Record::from_raw_cols_vals_unchecked(cols, vals),
internal_span: Span::empty(),
}
}
rusty_value::Fields::Unnamed(unnamed) => {
let mut vals = unnamed
.into_iter()
.map(|v| v.into_value())
.collect::<Vec<_>>();
// newtypes should be handled differently
// and only return the inner value instead of a range of values
if vals.len() == 1 {
vals.pop().unwrap()
} else {
Value::List {
vals,
internal_span: Span::empty(),
}
}
}
rusty_value::Fields::Unit => Value::Nothing {
internal_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,
internal_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,
internal_span: Span::empty(),
}
}
}
impl<R: RustyValue> IntoValue for R {
#[inline]
fn into_value(self) -> Value {
self.into_rusty_value().into_value()
}
}