use crate::{Range, Record, ShellError, Span, Value, ast::CellPath, engine::Closure};
use chrono::{DateTime, FixedOffset};
use nu_path::form::PathForm;
use std::{
borrow::{Borrow, Cow},
collections::HashMap,
};
pub trait IntoValue: Sized {
fn into_value(self, span: Span) -> Value;
}
impl<T, const N: usize> IntoValue for [T; N]
where
T: IntoValue,
{
fn into_value(self, span: Span) -> Value {
Vec::from(self).into_value(span)
}
}
macro_rules! primitive_into_value {
($type:ty, $method:ident) => {
primitive_into_value!($type => $type, $method);
};
($type:ty => $as_type:ty, $method:ident) => {
impl IntoValue for $type {
fn into_value(self, span: Span) -> Value {
Value::$method(<$as_type>::from(self), span)
}
}
};
}
primitive_into_value!(bool, bool);
primitive_into_value!(char, string);
primitive_into_value!(f32 => f64, float);
primitive_into_value!(f64, float);
primitive_into_value!(i8 => i64, int);
primitive_into_value!(i16 => i64, int);
primitive_into_value!(i32 => i64, int);
primitive_into_value!(i64, int);
primitive_into_value!(u8 => i64, int);
primitive_into_value!(u16 => i64, int);
primitive_into_value!(u32 => i64, int);
impl IntoValue for isize {
fn into_value(self, span: Span) -> Value {
Value::int(self as i64, span)
}
}
impl IntoValue for () {
fn into_value(self, span: Span) -> Value {
Value::nothing(span)
}
}
macro_rules! tuple_into_value {
($($t:ident:$n:tt),+) => {
impl<$($t),+> IntoValue for ($($t,)+) where $($t: IntoValue,)+ {
fn into_value(self, span: Span) -> Value {
let vals = vec![$(self.$n.into_value(span)),+];
Value::list(vals, span)
}
}
}
}
tuple_into_value!(T0:0);
tuple_into_value!(T0:0, T1:1);
tuple_into_value!(T0:0, T1:1, T2:2);
tuple_into_value!(T0:0, T1:1, T2:2, T3:3);
tuple_into_value!(T0:0, T1:1, T2:2, T3:3, T4:4);
tuple_into_value!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
tuple_into_value!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
tuple_into_value!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
tuple_into_value!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
tuple_into_value!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9);
tuple_into_value!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10);
tuple_into_value!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10, T11:11);
impl IntoValue for String {
fn into_value(self, span: Span) -> Value {
Value::string(self, span)
}
}
impl IntoValue for &str {
fn into_value(self, span: Span) -> Value {
Value::string(self, span)
}
}
impl<T> IntoValue for Vec<T>
where
T: IntoValue,
{
fn into_value(self, span: Span) -> Value {
Value::list(self.into_iter().map(|v| v.into_value(span)).collect(), span)
}
}
impl<T> IntoValue for Box<T>
where
T: IntoValue,
{
fn into_value(self, span: Span) -> Value {
let t: T = *self;
t.into_value(span)
}
}
impl<T> IntoValue for Option<T>
where
T: IntoValue,
{
fn into_value(self, span: Span) -> Value {
match self {
Some(v) => v.into_value(span),
None => Value::nothing(span),
}
}
}
impl<B> IntoValue for Cow<'_, B>
where
B: ?Sized + ToOwned,
B::Owned: IntoValue,
{
fn into_value(self, span: Span) -> Value {
<B::Owned as IntoValue>::into_value(self.into_owned(), span)
}
}
impl<K, V> IntoValue for HashMap<K, V>
where
K: Borrow<str> + Into<String>,
V: IntoValue,
{
fn into_value(self, span: Span) -> Value {
self.into_iter()
.map(|(k, v)| (k.into(), v.into_value(span)))
.collect::<Record>()
.into_value(span)
}
}
impl IntoValue for std::time::Duration {
fn into_value(self, span: Span) -> Value {
let val: u128 = self.as_nanos();
debug_assert!(val <= i64::MAX as u128, "duration value too large");
let val: i64 = val.try_into().unwrap_or(i64::MAX);
Value::duration(val, span)
}
}
impl IntoValue for &std::path::Path {
fn into_value(self, span: Span) -> Value {
Value::string(self.to_string_lossy(), span)
}
}
impl IntoValue for std::path::PathBuf {
fn into_value(self, span: Span) -> Value {
Value::string(self.to_string_lossy(), span)
}
}
impl IntoValue for Range {
fn into_value(self, span: Span) -> Value {
Value::range(self, span)
}
}
impl IntoValue for Record {
fn into_value(self, span: Span) -> Value {
Value::record(self, span)
}
}
impl IntoValue for Closure {
fn into_value(self, span: Span) -> Value {
Value::closure(self, span)
}
}
impl IntoValue for ShellError {
fn into_value(self, span: Span) -> Value {
Value::error(self, span)
}
}
impl IntoValue for CellPath {
fn into_value(self, span: Span) -> Value {
Value::cell_path(self, span)
}
}
impl IntoValue for Value {
fn into_value(self, span: Span) -> Value {
self.with_span(span)
}
}
impl<Form: PathForm> IntoValue for &nu_path::Path<Form> {
fn into_value(self, span: Span) -> Value {
Value::string(self.to_string_lossy(), span)
}
}
impl<Form: PathForm> IntoValue for nu_path::PathBuf<Form> {
fn into_value(self, span: Span) -> Value {
Value::string(self.to_string_lossy(), span)
}
}
impl IntoValue for DateTime<FixedOffset> {
fn into_value(self, span: Span) -> Value {
Value::date(self, span)
}
}
impl IntoValue for bytes::Bytes {
fn into_value(self, span: Span) -> Value {
Value::binary(self.to_vec(), span)
}
}
impl IntoValue for serde_json::Value {
fn into_value(self, span: Span) -> Value {
match self {
serde_json::Value::Null => Value::nothing(span),
serde_json::Value::Bool(b) => Value::bool(b, span),
serde_json::Value::Number(num) => {
if let Some(n) = num.as_i64() {
return Value::int(n, span);
}
Value::float(
num.as_f64()
.expect("should always return some floating point number"),
span,
)
}
serde_json::Value::String(s) => Value::string(s, span),
serde_json::Value::Array(values) => Value::list(
values.into_iter().map(|v| v.into_value(span)).collect(),
span,
),
serde_json::Value::Object(map) => Value::record(
Record::from_iter(map.into_iter().map(|(k, v)| (k, v.into_value(span)))),
span,
),
}
}
}
pub trait TryIntoValue: Sized {
fn try_into_value(self, span: Span) -> Result<Value, ShellError>;
}
impl<T> TryIntoValue for T
where
T: IntoValue,
{
fn try_into_value(self, span: Span) -> Result<Value, ShellError> {
Ok(self.into_value(span))
}
}