Begin migration away from arg serialization (#3281)

* initial implementation

* Move a few commands over to new arg system

* Fix char also
This commit is contained in:
Jonathan Turner
2021-04-08 20:15:36 +12:00
committed by GitHub
parent 5fcf11fcb0
commit 09a1f5acb9
20 changed files with 442 additions and 224 deletions

View File

@ -24,7 +24,9 @@ dyn-clone = "1.0.4"
ansi_term = "0.12.1"
async-recursion = "0.3.2"
async-trait = "0.1.42"
bigdecimal = "0.2.0"
bytes = "0.5.6"
chrono = { version = "0.4.19", features = ["serde"] }
derive-new = "0.5.8"
dirs-next = { version = "2.0.0", optional = true }
dunce = "1.0.1"
@ -39,6 +41,9 @@ glob = "0.3.0"
indexmap = { version = "1.6.1", features = ["serde-1"] }
itertools = "0.10.0"
log = "0.4.14"
num-bigint = { version = "0.3.1", features = ["serde"] }
num-format = "0.4.0"
num-traits = "0.2.14"
parking_lot = "0.11.1"
rayon = "1.5.0"
serde = { version = "1.0.123", features = ["derive"] }

View File

@ -3,6 +3,7 @@ use crate::env::host::Host;
use crate::evaluate::scope::Scope;
use crate::evaluation_context::EvaluationContext;
use crate::shell::shell_manager::ShellManager;
use crate::FromValue;
use crate::{call_info::UnevaluatedCallInfo, config_holder::ConfigHolder};
use derive_new::new;
use getset::Getters;
@ -171,11 +172,44 @@ impl EvaluatedCommandArgs {
.ok_or_else(|| ShellError::unimplemented("Better error: expect_nth"))
}
pub fn get(&self, name: &str) -> Option<&Value> {
self.call_info.args.get(name)
pub fn get_flag<T: FromValue>(&self, name: &str) -> Option<Result<T, ShellError>> {
self.call_info
.args
.get(name)
.map(|x| FromValue::from_value(x))
}
pub fn has(&self, name: &str) -> bool {
pub fn has_flag(&self, name: &str) -> bool {
self.call_info.args.has(name)
}
pub fn req<T: FromValue>(&self, pos: usize) -> Result<T, ShellError> {
if let Some(v) = self.nth(pos) {
FromValue::from_value(v)
} else {
Err(ShellError::labeled_error(
"Position beyond end of command arguments",
"can't access beyond end of command arguments",
self.call_info.name_tag.span,
))
}
}
pub fn opt<T: FromValue>(&self, pos: usize) -> Option<Result<T, ShellError>> {
if let Some(v) = self.nth(pos) {
Some(FromValue::from_value(v))
} else {
None
}
}
pub fn rest<T: FromValue>(&self, starting_pos: usize) -> Result<Vec<T>, ShellError> {
let mut output = vec![];
for val in self.call_info.args.positional_iter().skip(starting_pos) {
output.push(FromValue::from_value(val)?);
}
Ok(output)
}
}

View File

@ -0,0 +1,281 @@
use std::path::PathBuf;
use chrono::{DateTime, FixedOffset};
use nu_errors::ShellError;
use nu_protocol::{
hir::CapturedBlock, ColumnPath, Dictionary, Primitive, Range, UntaggedValue, Value,
};
use nu_source::{Tagged, TaggedItem};
pub trait FromValue: Sized {
fn from_value(v: &Value) -> Result<Self, ShellError>;
}
impl FromValue for Value {
fn from_value(v: &Value) -> Result<Self, ShellError> {
Ok(v.clone())
}
}
impl FromValue for num_bigint::BigInt {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Primitive(Primitive::Int(i)),
..
}
| Value {
value: UntaggedValue::Primitive(Primitive::Filesize(i)),
..
}
| Value {
value: UntaggedValue::Primitive(Primitive::Duration(i)),
..
} => Ok(i.clone()),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to integer",
"can't convert to integer",
tag.span,
)),
}
}
}
impl FromValue for u64 {
fn from_value(v: &Value) -> Result<Self, ShellError> {
v.as_u64()
}
}
impl FromValue for usize {
fn from_value(v: &Value) -> Result<Self, ShellError> {
v.as_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()
}
}
impl FromValue for bigdecimal::BigDecimal {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Primitive(Primitive::Decimal(d)),
..
} => Ok(d.clone()),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to decimal",
"can't convert to decimal",
tag.span,
)),
}
}
}
impl FromValue for String {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Primitive(Primitive::String(s)),
..
} => Ok(s.clone()),
Value {
value: UntaggedValue::Primitive(Primitive::GlobPattern(s)),
..
} => Ok(s.clone()),
Value {
value: UntaggedValue::Primitive(Primitive::FilePath(p)),
..
} => Ok(p.to_string_lossy().to_string()),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to string",
"can't convert to string",
tag.span,
)),
}
}
}
impl FromValue for Tagged<String> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
let tag = v.tag.clone();
v.as_string().map(|s| s.tagged(tag))
}
}
impl FromValue for PathBuf {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Primitive(Primitive::String(s)),
..
} => Ok(PathBuf::from(s)),
Value {
value: UntaggedValue::Primitive(Primitive::FilePath(p)),
..
} => Ok(p.clone()),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to filepath",
"can't convert to filepath",
tag.span,
)),
}
}
}
impl FromValue for ColumnPath {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Primitive(Primitive::ColumnPath(c)),
..
} => Ok(c.clone()),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to column path",
"can't convert to column path",
tag.span,
)),
}
}
}
impl FromValue for bool {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Primitive(Primitive::Boolean(b)),
..
} => Ok(*b),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to boolean",
"can't convert to boolean",
tag.span,
)),
}
}
}
impl FromValue for Tagged<bool> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Primitive(Primitive::Boolean(b)),
tag,
} => Ok((*b).tagged(tag)),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to boolean",
"can't convert to boolean",
tag.span,
)),
}
}
}
impl FromValue for DateTime<FixedOffset> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Primitive(Primitive::Date(d)),
..
} => Ok(*d),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to date",
"can't convert to date",
tag.span,
)),
}
}
}
impl FromValue for Range {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Primitive(Primitive::Range(r)),
..
} => Ok((**r).clone()),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to range",
"can't convert to range",
tag.span,
)),
}
}
}
impl FromValue for Vec<u8> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Primitive(Primitive::Binary(b)),
..
} => Ok(b.clone()),
Value {
value: UntaggedValue::Primitive(Primitive::String(s)),
..
} => Ok(s.bytes().collect()),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to binary data",
"can't convert to binary data",
tag.span,
)),
}
}
}
impl FromValue for Dictionary {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Row(r),
..
} => Ok(r.clone()),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to row",
"can't convert to row",
tag.span,
)),
}
}
}
impl FromValue for CapturedBlock {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Block(b),
..
} => Ok((**b).clone()),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to block",
"can't convert to block",
tag.span,
)),
}
}
}
impl FromValue for Vec<Value> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value {
value: UntaggedValue::Table(t),
..
} => Ok(t.clone()),
Value { tag, .. } => Err(ShellError::labeled_error(
"Can't convert to table",
"can't convert to table",
tag.span,
)),
}
}
}

View File

@ -10,6 +10,7 @@ mod evaluate;
mod evaluation_context;
mod example;
pub mod filesystem;
mod from_value;
mod maybe_text_codec;
pub mod plugin;
mod print;
@ -36,6 +37,7 @@ pub use crate::example::Example;
pub use crate::filesystem::dir_info::{DirBuilder, DirInfo, FileInfo};
pub use crate::filesystem::filesystem_shell::FilesystemShell;
pub use crate::filesystem::path;
pub use crate::from_value::FromValue;
pub use crate::maybe_text_codec::{BufCodecReader, MaybeTextCodec, StringOrBinary};
pub use crate::print::maybe_print_errors;
pub use crate::runnable_context::RunnableContext;

View File

@ -71,19 +71,6 @@ impl Default for MaybeTextCodec {
}
}
// impl MaybeTextCodec {
// fn encode(&mut self, item: StringOrBinary, mut dst: &mut [u8]) {
// match item {
// StringOrBinary::String(s) => {
// dst.put(s.as_bytes());
// }
// StringOrBinary::Binary(b) => {
// dst.put(Bytes::from(b));
// }
// }
// }
// }
impl MaybeTextCodec {
pub fn decode(&mut self, src: &[u8]) -> Result<Option<StringOrBinary>, ShellError> {
if src.is_empty() {