forked from extern/nushell
Finish removing arg deserialization (#3552)
* WIP remove process * WIP * WIP * Finish removing arg deserialization
This commit is contained in:
@ -1,4 +1,3 @@
|
||||
use crate::deserializer::ConfigDeserializer;
|
||||
use crate::env::host::Host;
|
||||
use crate::evaluate::scope::Scope;
|
||||
use crate::evaluation_context::EvaluationContext;
|
||||
@ -13,7 +12,6 @@ use nu_protocol::{CallInfo, Value};
|
||||
use nu_source::Tag;
|
||||
use nu_stream::InputStream;
|
||||
use parking_lot::Mutex;
|
||||
use serde::Deserialize;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
@ -79,14 +77,14 @@ impl CommandArgs {
|
||||
Ok((f(&evaluated_args.args)?, evaluated_args.input))
|
||||
}
|
||||
|
||||
pub fn process<'de, T: Deserialize<'de>>(self) -> Result<(T, InputStream), ShellError> {
|
||||
let args = self.evaluate_once()?;
|
||||
let call_info = args.call_info.clone();
|
||||
// pub fn process<'de, T: Deserialize<'de>>(self) -> Result<(T, InputStream), ShellError> {
|
||||
// let args = self.evaluate_once()?;
|
||||
// let call_info = args.call_info.clone();
|
||||
|
||||
let mut deserializer = ConfigDeserializer::from_call_info(call_info);
|
||||
// let mut deserializer = ConfigDeserializer::from_call_info(call_info);
|
||||
|
||||
Ok((T::deserialize(&mut deserializer)?, args.input))
|
||||
}
|
||||
// Ok((T::deserialize(&mut deserializer)?, args.input))
|
||||
// }
|
||||
}
|
||||
|
||||
pub struct EvaluatedCommandArgs {
|
||||
|
@ -1,621 +0,0 @@
|
||||
use log::trace;
|
||||
use nu_errors::{CoerceInto, ShellError};
|
||||
use nu_protocol::{
|
||||
hir::CapturedBlock, CallInfo, ColumnPath, Primitive, RangeInclusion, ShellTypeName,
|
||||
UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::Span;
|
||||
use nu_source::{HasSpan, Spanned, SpannedItem, Tagged, TaggedItem};
|
||||
use nu_value_ext::ValueExt;
|
||||
use serde::de;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Copy, Clone, Deserialize, Serialize)]
|
||||
pub struct NumericRange {
|
||||
pub from: (Option<Spanned<u64>>, RangeInclusion),
|
||||
pub to: (Option<Spanned<u64>>, RangeInclusion),
|
||||
}
|
||||
|
||||
impl NumericRange {
|
||||
pub fn min(self) -> u64 {
|
||||
match self.from.1 {
|
||||
RangeInclusion::Inclusive => self.from.0.map(|from| *from).unwrap_or(0),
|
||||
RangeInclusion::Exclusive => {
|
||||
self.from.0.map(|from| *from).unwrap_or(0).saturating_add(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max(self) -> u64 {
|
||||
match self.to.1 {
|
||||
RangeInclusion::Inclusive => self.to.0.map(|to| *to).unwrap_or(u64::MAX),
|
||||
RangeInclusion::Exclusive => self
|
||||
.to
|
||||
.0
|
||||
.map(|to| *to)
|
||||
.unwrap_or(u64::MAX)
|
||||
.saturating_sub(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DeserializerItem<'de> {
|
||||
key_struct_field: Option<(String, &'de str)>,
|
||||
val: Value,
|
||||
}
|
||||
|
||||
pub struct ConfigDeserializer<'de> {
|
||||
call: CallInfo,
|
||||
stack: Vec<DeserializerItem<'de>>,
|
||||
saw_root: bool,
|
||||
position: usize,
|
||||
}
|
||||
|
||||
impl<'de> ConfigDeserializer<'de> {
|
||||
pub fn from_call_info(call: CallInfo) -> ConfigDeserializer<'de> {
|
||||
ConfigDeserializer {
|
||||
call,
|
||||
stack: vec![],
|
||||
saw_root: false,
|
||||
position: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_val(&mut self, val: Value) {
|
||||
self.stack.push(DeserializerItem {
|
||||
key_struct_field: None,
|
||||
val,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn push(&mut self, name: &'static str) -> Result<(), ShellError> {
|
||||
let value: Option<Value> = if name == "rest" {
|
||||
let positional = self.call.args.slice_from(self.position);
|
||||
self.position += positional.len();
|
||||
Some(UntaggedValue::Table(positional).into_untagged_value()) // TODO: correct tag
|
||||
} else if self.call.args.has(name) {
|
||||
self.call.args.get(name).cloned()
|
||||
} else {
|
||||
let position = self.position;
|
||||
self.position += 1;
|
||||
self.call.args.nth(position).cloned()
|
||||
};
|
||||
|
||||
trace!("pushing {:?}", value);
|
||||
|
||||
self.stack.push(DeserializerItem {
|
||||
key_struct_field: Some((name.to_string(), name)),
|
||||
val: value.unwrap_or_else(|| UntaggedValue::nothing().into_value(&self.call.name_tag)),
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn top(&mut self) -> &DeserializerItem {
|
||||
let value = self.stack.last();
|
||||
trace!("inspecting top value :: {:?}", value);
|
||||
value.expect("Can't get top element of an empty stack")
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> DeserializerItem {
|
||||
let value = self.stack.pop();
|
||||
trace!("popping value :: {:?}", value);
|
||||
value.expect("Can't pop an empty stack")
|
||||
}
|
||||
}
|
||||
|
||||
use de::Visitor;
|
||||
|
||||
impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> {
|
||||
type Error = ShellError;
|
||||
fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_any")
|
||||
}
|
||||
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let value = self.pop();
|
||||
trace!("Extracting {:?} for bool", value.val);
|
||||
|
||||
match &value.val {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Boolean(b)),
|
||||
..
|
||||
} => visitor.visit_bool(*b),
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Nothing),
|
||||
..
|
||||
} => visitor.visit_bool(false),
|
||||
other => Err(ShellError::type_error(
|
||||
"Boolean",
|
||||
other.type_name().spanned(other.span()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
fn deserialize_i8<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_i8")
|
||||
}
|
||||
fn deserialize_i16<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_i16")
|
||||
}
|
||||
fn deserialize_i32<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_i32")
|
||||
}
|
||||
fn deserialize_i64<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_i64")
|
||||
}
|
||||
fn deserialize_u8<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_u8")
|
||||
}
|
||||
fn deserialize_u16<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_u16")
|
||||
}
|
||||
fn deserialize_u32<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_u32")
|
||||
}
|
||||
fn deserialize_u64<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_u64")
|
||||
}
|
||||
fn deserialize_f32<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_f32")
|
||||
}
|
||||
fn deserialize_f64<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_f64")
|
||||
}
|
||||
fn deserialize_char<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_char")
|
||||
}
|
||||
fn deserialize_str<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_str")
|
||||
}
|
||||
fn deserialize_string<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_string")
|
||||
}
|
||||
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_bytes")
|
||||
}
|
||||
fn deserialize_byte_buf<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_byte_buf")
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let value = self.top();
|
||||
let name = std::any::type_name::<V::Value>();
|
||||
trace!("<Option> Extracting {:?} for Option<{}>", value, name);
|
||||
match &value.val.value {
|
||||
UntaggedValue::Primitive(Primitive::Nothing) => visitor.visit_none(),
|
||||
_ => visitor.visit_some(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_unit<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_unit")
|
||||
}
|
||||
fn deserialize_unit_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_unit_struct")
|
||||
}
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_newtype_struct")
|
||||
}
|
||||
fn deserialize_seq<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let value = self.pop();
|
||||
trace!("<Vec> Extracting {:?} for vec", value.val);
|
||||
|
||||
match value.val.into_parts() {
|
||||
(UntaggedValue::Table(items), _) => {
|
||||
let de = SeqDeserializer::new(&mut self, items.into_iter());
|
||||
visitor.visit_seq(de)
|
||||
}
|
||||
(other, tag) => Err(ShellError::type_error(
|
||||
"Vec",
|
||||
other.type_name().spanned(tag),
|
||||
)),
|
||||
}
|
||||
}
|
||||
fn deserialize_tuple<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let value = self.pop();
|
||||
trace!(
|
||||
"<Tuple> Extracting {:?} for tuple with {} elements",
|
||||
value.val,
|
||||
len
|
||||
);
|
||||
|
||||
match value.val.into_parts() {
|
||||
(UntaggedValue::Table(items), _) => {
|
||||
let de = SeqDeserializer::new(&mut self, items.into_iter());
|
||||
visitor.visit_seq(de)
|
||||
}
|
||||
(other, tag) => Err(ShellError::type_error(
|
||||
"Tuple",
|
||||
other.type_name().spanned(tag),
|
||||
)),
|
||||
}
|
||||
}
|
||||
fn deserialize_tuple_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_tuple_struct")
|
||||
}
|
||||
fn deserialize_map<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_map")
|
||||
}
|
||||
fn deserialize_struct<V>(
|
||||
mut self,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
fn visit<'de, T, V>(
|
||||
val: T,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, ShellError>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let json = serde_json::to_string(&val)?;
|
||||
let json_cursor = std::io::Cursor::new(json.into_bytes());
|
||||
let mut json_de = serde_json::Deserializer::from_reader(json_cursor);
|
||||
let r = json_de.deserialize_struct(name, fields, visitor)?;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
trace!(
|
||||
"deserializing struct {:?} {:?} (saw_root={} stack={:?})",
|
||||
name,
|
||||
fields,
|
||||
self.saw_root,
|
||||
self.stack
|
||||
);
|
||||
|
||||
if !self.saw_root {
|
||||
self.saw_root = true;
|
||||
return visitor.visit_seq(StructDeserializer::new(&mut self, fields));
|
||||
}
|
||||
|
||||
let value = self.pop();
|
||||
|
||||
let type_name = std::any::type_name::<V::Value>();
|
||||
let tagged_val_name = std::any::type_name::<Value>();
|
||||
|
||||
trace!(
|
||||
"name={} type_name={} tagged_val_name={}",
|
||||
name,
|
||||
type_name,
|
||||
tagged_val_name
|
||||
);
|
||||
|
||||
if type_name == tagged_val_name {
|
||||
return visit::<Value, _>(value.val, name, fields, visitor);
|
||||
}
|
||||
|
||||
if name == "CapturedBlock" {
|
||||
let block = match value.val {
|
||||
Value {
|
||||
value: UntaggedValue::Block(block),
|
||||
..
|
||||
} => block,
|
||||
other => {
|
||||
return Err(ShellError::type_error(
|
||||
"Block",
|
||||
other.type_name().spanned(other.span()),
|
||||
))
|
||||
}
|
||||
};
|
||||
return visit::<CapturedBlock, _>(*block, name, fields, visitor);
|
||||
}
|
||||
|
||||
if name == "ColumnPath" {
|
||||
let path = match value.val {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::ColumnPath(path)),
|
||||
..
|
||||
} => path,
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(path)),
|
||||
..
|
||||
} => {
|
||||
let s = path.spanned(Span::unknown());
|
||||
ColumnPath::build(&s)
|
||||
}
|
||||
other => {
|
||||
return Err(ShellError::type_error(
|
||||
"column path",
|
||||
other.type_name().spanned(other.span()),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
return visit::<ColumnPath, _>(path, name, fields, visitor);
|
||||
}
|
||||
|
||||
trace!("Extracting {:?} for {:?}", value.val, type_name);
|
||||
|
||||
let tag = value.val.tag();
|
||||
match value.val {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Boolean(b)),
|
||||
..
|
||||
} => visit::<Tagged<bool>, _>(b.tagged(tag), name, fields, visitor),
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Nothing),
|
||||
..
|
||||
} => visit::<Tagged<bool>, _>(false.tagged(tag), name, fields, visitor),
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(p)),
|
||||
..
|
||||
} => visit::<Tagged<PathBuf>, _>(p.tagged(tag), name, fields, visitor),
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Int(int)),
|
||||
..
|
||||
} => visit::<Tagged<i64>, _>(int.tagged(tag), name, fields, visitor),
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::BigInt(int)),
|
||||
..
|
||||
} => {
|
||||
let i: i64 = int.tagged(value.val.tag).coerce_into("converting to i64")?;
|
||||
visit::<Tagged<i64>, _>(i.tagged(tag), name, fields, visitor)
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Duration(big_int)),
|
||||
..
|
||||
} => {
|
||||
let u_int: u64 = big_int
|
||||
.tagged(value.val.tag)
|
||||
.coerce_into("converting to u64")?;
|
||||
visit::<Tagged<u64>, _>(u_int.tagged(tag), name, fields, visitor)
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Decimal(decimal)),
|
||||
..
|
||||
} => {
|
||||
let i: f64 = decimal
|
||||
.tagged(value.val.tag)
|
||||
.coerce_into("converting to f64")?;
|
||||
visit::<Tagged<f64>, _>(i.tagged(tag), name, fields, visitor)
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(string)),
|
||||
..
|
||||
} => visit::<Tagged<String>, _>(string.tagged(tag), name, fields, visitor),
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Range(range)),
|
||||
..
|
||||
} => {
|
||||
let (left, left_inclusion) = range.from;
|
||||
let (right, right_inclusion) = range.to;
|
||||
let left_span = left.span;
|
||||
let right_span = right.span;
|
||||
|
||||
let left = match left.item {
|
||||
Primitive::Nothing => None,
|
||||
_ => Some(left.as_u64(left_span)?),
|
||||
};
|
||||
let right = match right.item {
|
||||
Primitive::Nothing => None,
|
||||
_ => Some(right.as_u64(right_span)?),
|
||||
};
|
||||
|
||||
let numeric_range = NumericRange {
|
||||
from: (left.map(|left| left.spanned(left_span)), left_inclusion),
|
||||
to: (
|
||||
right.map(|right| right.spanned(right_span)),
|
||||
right_inclusion,
|
||||
),
|
||||
};
|
||||
|
||||
visit::<Tagged<NumericRange>, _>(numeric_range.tagged(tag), name, fields, visitor)
|
||||
}
|
||||
|
||||
other => Err(ShellError::type_error(
|
||||
name,
|
||||
other.type_name().spanned(other.span()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variants: &'static [&'static str],
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_enum")
|
||||
}
|
||||
fn deserialize_identifier<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_identifier")
|
||||
}
|
||||
fn deserialize_ignored_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_ignored_any")
|
||||
}
|
||||
}
|
||||
|
||||
struct SeqDeserializer<'a, 'de: 'a, I: Iterator<Item = Value>> {
|
||||
de: &'a mut ConfigDeserializer<'de>,
|
||||
vals: I,
|
||||
}
|
||||
|
||||
impl<'a, 'de: 'a, I: Iterator<Item = Value>> SeqDeserializer<'a, 'de, I> {
|
||||
fn new(de: &'a mut ConfigDeserializer<'de>, vals: I) -> Self {
|
||||
SeqDeserializer { de, vals }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'de: 'a, I: Iterator<Item = Value>> de::SeqAccess<'de> for SeqDeserializer<'a, 'de, I> {
|
||||
type Error = ShellError;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: de::DeserializeSeed<'de>,
|
||||
{
|
||||
let next = if let Some(next) = self.vals.next() {
|
||||
next
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
self.de.push_val(next);
|
||||
seed.deserialize(&mut *self.de).map(Some)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> Option<usize> {
|
||||
self.vals.size_hint().1
|
||||
}
|
||||
}
|
||||
|
||||
struct StructDeserializer<'a, 'de: 'a> {
|
||||
de: &'a mut ConfigDeserializer<'de>,
|
||||
fields: &'static [&'static str],
|
||||
}
|
||||
|
||||
impl<'a, 'de: 'a> StructDeserializer<'a, 'de> {
|
||||
fn new(de: &'a mut ConfigDeserializer<'de>, fields: &'static [&'static str]) -> Self {
|
||||
StructDeserializer { de, fields }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'de: 'a> de::SeqAccess<'de> for StructDeserializer<'a, 'de> {
|
||||
type Error = ShellError;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: de::DeserializeSeed<'de>,
|
||||
{
|
||||
if self.fields.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
trace!("Processing {}", self.fields[0]);
|
||||
|
||||
self.de.push(self.fields[0])?;
|
||||
self.fields = &self.fields[1..];
|
||||
seed.deserialize(&mut *self.de).map(Some)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> Option<usize> {
|
||||
Some(self.fields.len())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::any::type_name;
|
||||
#[test]
|
||||
fn check_type_name_properties() {
|
||||
// This ensures that certain properties for the
|
||||
// std::any::type_name function hold, that
|
||||
// this code relies on. The type_name docs explicitly
|
||||
// mention that the actual format of the output
|
||||
// is unspecified and change is likely.
|
||||
// This test makes sure that such change is detected
|
||||
// by this test failing, and not things silently breaking.
|
||||
// Specifically, we rely on this behavior further above
|
||||
// in the file for the Value special case parsing.
|
||||
let tuple = type_name::<()>();
|
||||
let tagged_tuple = type_name::<Tagged<()>>();
|
||||
let tagged_value = type_name::<Value>();
|
||||
assert_ne!(tuple, tagged_tuple);
|
||||
assert_ne!(tuple, tagged_value);
|
||||
assert_ne!(tagged_tuple, tagged_value);
|
||||
}
|
||||
}
|
@ -378,7 +378,7 @@ impl Shell for FilesystemShell {
|
||||
|
||||
let any_source_is_dir = sources.iter().any(|f| matches!(f, Ok(f) if f.is_dir()));
|
||||
|
||||
if any_source_is_dir && !recursive.item {
|
||||
if any_source_is_dir && !recursive {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Directories must be copied using \"--recursive\"",
|
||||
"resolves to a directory (not copied)",
|
||||
@ -607,11 +607,11 @@ impl Shell for FilesystemShell {
|
||||
`rm_always_trash = true`, but the current nu executable was not \
|
||||
built with feature `trash_support`.",
|
||||
));
|
||||
} else if _trash.item {
|
||||
} else if _trash {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Cannot execute `rm` with option `--trash`; feature `trash-support` not enabled",
|
||||
"this option is only available if nu is built with the `trash-support` feature",
|
||||
_trash.tag
|
||||
name
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -686,7 +686,7 @@ impl Shell for FilesystemShell {
|
||||
};
|
||||
}
|
||||
|
||||
if all_targets.is_empty() && !_force.item {
|
||||
if all_targets.is_empty() && !_force {
|
||||
return Err(ShellError::labeled_error(
|
||||
"No valid paths",
|
||||
"no valid paths",
|
||||
@ -715,7 +715,7 @@ impl Shell for FilesystemShell {
|
||||
|
||||
if metadata.is_file()
|
||||
|| metadata.file_type().is_symlink()
|
||||
|| recursive.item
|
||||
|| recursive
|
||||
|| is_socket
|
||||
|| is_fifo
|
||||
|| is_empty()
|
||||
@ -724,7 +724,7 @@ impl Shell for FilesystemShell {
|
||||
#[cfg(feature = "trash-support")]
|
||||
{
|
||||
use std::io::Error;
|
||||
result = if _trash.item || (rm_always_trash && !_permanent.item) {
|
||||
result = if _trash || (rm_always_trash && !_permanent) {
|
||||
trash::delete(&f).map_err(|e: trash::Error| {
|
||||
Error::new(ErrorKind::Other, format!("{:?}", e))
|
||||
})
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use bigdecimal::ToPrimitive;
|
||||
use bigdecimal::{BigDecimal, ToPrimitive};
|
||||
use chrono::{DateTime, FixedOffset};
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
@ -19,6 +19,32 @@ impl FromValue for Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromValue for Tagged<num_bigint::BigInt> {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
let tag = v.tag.clone();
|
||||
|
||||
match v {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Int(i)),
|
||||
..
|
||||
} => Ok(BigInt::from(*i).tagged(tag)),
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Filesize(i)),
|
||||
..
|
||||
} => Ok(BigInt::from(*i).tagged(tag)),
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Duration(i)),
|
||||
..
|
||||
} => Ok(BigInt::from(*i).tagged(tag)),
|
||||
Value { tag, .. } => Err(ShellError::labeled_error(
|
||||
"Can't convert to integer",
|
||||
"can't convert to integer",
|
||||
tag.span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromValue for num_bigint::BigInt {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
match v {
|
||||
@ -33,7 +59,7 @@ impl FromValue for num_bigint::BigInt {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Duration(i)),
|
||||
..
|
||||
} => Ok(i.clone()),
|
||||
} => Ok(BigInt::from(*i)),
|
||||
Value { tag, .. } => Err(ShellError::labeled_error(
|
||||
"Can't convert to integer",
|
||||
"can't convert to integer",
|
||||
@ -56,6 +82,18 @@ impl FromValue for u64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromValue for i64 {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
v.as_i64()
|
||||
}
|
||||
}
|
||||
impl FromValue for Tagged<i64> {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
let tag = v.tag.clone();
|
||||
v.as_i64().map(|s| s.tagged(tag))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromValue for Tagged<u32> {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
let tag = v.tag.clone();
|
||||
@ -90,12 +128,6 @@ impl FromValue for usize {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromValue for i64 {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
v.as_i64()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromValue for i32 {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
v.as_i32()
|
||||
@ -109,6 +141,10 @@ impl FromValue for bigdecimal::BigDecimal {
|
||||
value: UntaggedValue::Primitive(Primitive::Decimal(d)),
|
||||
..
|
||||
} => Ok(d.clone()),
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Int(i)),
|
||||
..
|
||||
} => Ok(BigDecimal::from(*i)),
|
||||
Value { tag, .. } => Err(ShellError::labeled_error(
|
||||
"Can't convert to decimal",
|
||||
"can't convert to decimal",
|
||||
@ -123,6 +159,7 @@ impl FromValue for Tagged<bigdecimal::BigDecimal> {
|
||||
let tag = v.tag.clone();
|
||||
match &v.value {
|
||||
UntaggedValue::Primitive(Primitive::Decimal(d)) => Ok(d.clone().tagged(tag)),
|
||||
UntaggedValue::Primitive(Primitive::Int(i)) => Ok(BigDecimal::from(*i).tagged(tag)),
|
||||
_ => Err(ShellError::labeled_error(
|
||||
"Can't convert to decimal",
|
||||
"can't convert to decimal",
|
||||
|
@ -1,7 +1,6 @@
|
||||
mod call_info;
|
||||
mod command_args;
|
||||
mod config_holder;
|
||||
pub mod deserializer;
|
||||
pub mod documentation;
|
||||
mod env;
|
||||
mod evaluate;
|
||||
|
@ -11,7 +11,7 @@ pub struct CdArgs {
|
||||
pub struct CopyArgs {
|
||||
pub src: Tagged<PathBuf>,
|
||||
pub dst: Tagged<PathBuf>,
|
||||
pub recursive: Tagged<bool>,
|
||||
pub recursive: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -41,10 +41,10 @@ pub struct MkdirArgs {
|
||||
#[derive(Deserialize)]
|
||||
pub struct RemoveArgs {
|
||||
pub rest: Vec<Tagged<PathBuf>>,
|
||||
pub recursive: Tagged<bool>,
|
||||
pub recursive: bool,
|
||||
#[allow(unused)]
|
||||
pub trash: Tagged<bool>,
|
||||
pub trash: bool,
|
||||
#[allow(unused)]
|
||||
pub permanent: Tagged<bool>,
|
||||
pub force: Tagged<bool>,
|
||||
pub permanent: bool,
|
||||
pub force: bool,
|
||||
}
|
||||
|
Reference in New Issue
Block a user