forked from extern/nushell
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:
@ -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)
|
||||
}
|
||||
}
|
||||
|
281
crates/nu-engine/src/from_value.rs
Normal file
281
crates/nu-engine/src/from_value.rs
Normal 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,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
Reference in New Issue
Block a user