A few optimisations (#3306)

* A few optimisations

* Fix test
This commit is contained in:
Jonathan Turner 2021-04-12 19:47:31 +12:00 committed by GitHub
parent b2fe5fabb1
commit fc15e0e27d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 52 deletions

View File

@ -1,7 +1,7 @@
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value};
#[derive(Deserialize)]
struct Arguments {
@ -27,13 +27,14 @@ impl WholeStreamCommand for Command {
"Append a row to the table."
}
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
let (Arguments { mut value }, input) = args.process()?;
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let (Arguments { mut value }, mut input) = args.process()?;
let input: Vec<Value> = input.collect();
let mut prepend = vec![];
if let Some(first) = input.get(0) {
if let Some(first) = input.next() {
value.tag = first.tag();
prepend.push(first);
}
// Checks if we are trying to append a row literal
@ -47,11 +48,10 @@ impl WholeStreamCommand for Command {
}
}
Ok(input
Ok(prepend
.into_iter()
.chain(vec![value])
.map(ReturnSuccess::value)
.to_action_stream())
.chain(input.into_iter().chain(vec![value]))
.to_output_stream())
}
fn examples(&self) -> Vec<Example> {

View File

@ -2,7 +2,7 @@ use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, ReturnValue, Signature, UntaggedValue};
use nu_protocol::{Signature, UntaggedValue, Value};
pub struct Length;
@ -28,7 +28,7 @@ impl WholeStreamCommand for Length {
"Show the total number of rows or items."
}
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let (LengthArgs { column }, input) = args.process()?;
@ -38,7 +38,7 @@ impl WholeStreamCommand for Length {
done: false,
tag,
}
.to_action_stream())
.to_output_stream())
}
fn examples(&self) -> Vec<Example> {
@ -65,7 +65,7 @@ struct CountIterator {
}
impl Iterator for CountIterator {
type Item = ReturnValue;
type Item = Value;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
@ -79,7 +79,7 @@ impl Iterator for CountIterator {
match &first.value {
UntaggedValue::Row(dictionary) => dictionary.length(),
_ => {
return Some(Err(ShellError::labeled_error(
return Some(Value::error(ShellError::labeled_error(
"Cannot obtain column length",
"cannot obtain column length",
self.tag.clone(),
@ -94,9 +94,7 @@ impl Iterator for CountIterator {
input.count()
};
Some(Ok(ReturnSuccess::Value(
UntaggedValue::int(length).into_value(self.tag.clone()),
)))
Some(UntaggedValue::int(length).into_value(self.tag.clone()))
}
}

View File

@ -27,7 +27,7 @@ impl WholeStreamCommand for Prepend {
"Prepend the given row to the front of the table."
}
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
prepend(args)
}
@ -45,12 +45,12 @@ impl WholeStreamCommand for Prepend {
}
}
fn prepend(args: CommandArgs) -> Result<ActionStream, ShellError> {
fn prepend(args: CommandArgs) -> Result<OutputStream, ShellError> {
let (PrependArgs { row }, input) = args.process()?;
let bos = vec![row].into_iter();
Ok(bos.chain(input).to_action_stream())
Ok(bos.chain(input).to_output_stream())
}
#[cfg(test)]

View File

@ -3,7 +3,9 @@ use nu_engine::evaluate_baseline_expr;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
hir::CapturedBlock, hir::ClassifiedCommand, ReturnSuccess, Signature, SyntaxShape,
hir::CapturedBlock,
hir::{ClassifiedCommand, SpannedExpression},
Signature, SyntaxShape, Value,
};
pub struct Command;
@ -30,7 +32,7 @@ impl WholeStreamCommand for Command {
"Filter table to match the condition."
}
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
where_command(args)
}
@ -59,8 +61,8 @@ impl WholeStreamCommand for Command {
]
}
}
fn where_command(raw_args: CommandArgs) -> Result<ActionStream, ShellError> {
let ctx = Arc::new(EvaluationContext::from_args(&raw_args));
fn where_command(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
let context = Arc::new(EvaluationContext::from_args(&raw_args));
let tag = raw_args.call_info.name_tag.clone();
let (Arguments { block }, input) = raw_args.process()?;
let condition = {
@ -92,34 +94,13 @@ fn where_command(raw_args: CommandArgs) -> Result<ActionStream, ShellError> {
}
};
Ok(input
.filter_map(move |input| {
let condition = condition.clone();
let ctx = ctx.clone();
ctx.scope.enter_scope();
ctx.scope.add_vars(&block.captured.entries);
ctx.scope.add_var("$it", input.clone());
//FIXME: should we use the scope that's brought in as well?
let condition = evaluate_baseline_expr(&condition, &*ctx);
ctx.scope.exit_scope();
match condition {
Ok(condition) => match condition.as_bool() {
Ok(b) => {
if b {
Some(Ok(ReturnSuccess::Value(input)))
} else {
None
}
}
Err(e) => Some(Err(e)),
},
Err(e) => Some(Err(e)),
}
})
.to_action_stream())
Ok(WhereIterator {
block,
condition,
context,
input,
}
.to_output_stream())
}
#[cfg(test)]
@ -134,3 +115,40 @@ mod tests {
test_examples(Command {})
}
}
struct WhereIterator {
condition: Box<SpannedExpression>,
context: Arc<EvaluationContext>,
input: InputStream,
block: CapturedBlock,
}
impl Iterator for WhereIterator {
type Item = Value;
fn next(&mut self) -> Option<Self::Item> {
while let Some(x) = self.input.next() {
self.context.scope.enter_scope();
self.context.scope.add_vars(&self.block.captured.entries);
self.context.scope.add_var("$it", x.clone());
//FIXME: should we use the scope that's brought in as well?
let condition = evaluate_baseline_expr(&self.condition, &self.context);
self.context.scope.exit_scope();
match condition {
Ok(condition) => match condition.as_bool() {
Ok(b) => {
if b {
return Some(x);
}
}
Err(e) => return Some(Value::error(e)),
},
Err(e) => return Some(Value::error(e)),
}
}
None
}
}