From 2cd1f634d04b8a9cecaae423948a0083fa6ca0b4 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 9 Oct 2021 19:20:32 +1300 Subject: [PATCH] Add map and flat_map to value --- crates/nu-command/src/strings/split/chars.rs | 37 +--------- crates/nu-command/src/strings/split/column.rs | 42 ++---------- crates/nu-command/src/strings/split/row.rs | 37 ++-------- crates/nu-protocol/src/value/mod.rs | 67 +++++++++++++++++++ 4 files changed, 78 insertions(+), 105 deletions(-) diff --git a/crates/nu-command/src/strings/split/chars.rs b/crates/nu-command/src/strings/split/chars.rs index 108190c6aa..39df74ab9f 100644 --- a/crates/nu-command/src/strings/split/chars.rs +++ b/crates/nu-command/src/strings/split/chars.rs @@ -1,7 +1,7 @@ use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - Example, IntoValueStream, ShellError, Signature, Span, Type, Value, + Example, ShellError, Signature, Span, Type, Value, }; pub struct SubCommand; @@ -59,40 +59,9 @@ impl Command for SubCommand { } fn split_chars(call: &Call, input: Value) -> Result { - let name = call.head; + let span = call.head; - Ok(match input { - Value::List { vals, span } => Value::List { - vals: vals - .iter() - .flat_map(|x| split_chars_helper(x, name)) - .collect(), - span, - }, - Value::Stream { stream, span } => Value::Stream { - stream: stream - .flat_map(move |x| split_chars_helper(&x, name)) - .into_value_stream(), - span, - }, - v => { - let v_span = v.span(); - if v.as_string().is_ok() { - Value::List { - vals: split_chars_helper(&v, name), - span: v_span, - } - } else { - Value::Error { - error: ShellError::PipelineMismatch { - expected: Type::String, - expected_span: name, - origin: v.span(), - }, - } - } - } - }) + Ok(input.flat_map(span, move |x| split_chars_helper(&x, span))) } fn split_chars_helper(v: &Value, name: Span) -> Vec { diff --git a/crates/nu-command/src/strings/split/column.rs b/crates/nu-command/src/strings/split/column.rs index fb3836ee3e..b8efed3775 100644 --- a/crates/nu-command/src/strings/split/column.rs +++ b/crates/nu-command/src/strings/split/column.rs @@ -2,7 +2,7 @@ use nu_engine::CallExt; use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - IntoValueStream, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value, + ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value, }; pub struct SubCommand; @@ -51,43 +51,9 @@ fn split_column( let rest: Vec> = call.rest(context, 1)?; let collapse_empty = call.has_flag("collapse-empty"); - Ok(match input { - Value::List { vals, span } => Value::List { - vals: vals - .iter() - .map(move |x| split_column_helper(x, &separator, &rest, collapse_empty, name_span)) - .collect(), - span, - }, - Value::Stream { stream, span } => Value::Stream { - stream: stream - .map(move |x| split_column_helper(&x, &separator, &rest, collapse_empty, name_span)) - .into_value_stream(), - span, - }, - v => { - if v.as_string().is_ok() { - Value::List { - vals: vec![split_column_helper( - &v, - &separator, - &rest, - collapse_empty, - name_span, - )], - span: call.head, - } - } else { - Value::Error { - error: ShellError::PipelineMismatch { - expected: Type::String, - expected_span: call.head, - origin: v.span(), - }, - } - } - } - }) + Ok(input.map(name_span, move |x| { + split_column_helper(&x, &separator, &rest, collapse_empty, name_span) + })) } fn split_column_helper( diff --git a/crates/nu-command/src/strings/split/row.rs b/crates/nu-command/src/strings/split/row.rs index a4602e2ca4..4467598536 100644 --- a/crates/nu-command/src/strings/split/row.rs +++ b/crates/nu-command/src/strings/split/row.rs @@ -2,7 +2,7 @@ use nu_engine::CallExt; use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - IntoValueStream, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value, + ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value, }; pub struct SubCommand; @@ -42,38 +42,9 @@ fn split_row( let name_span = call.head; let separator: Spanned = call.req(context, 0)?; - Ok(match input { - Value::List { vals, span } => Value::List { - vals: vals - .iter() - .flat_map(move |x| split_row_helper(x, &separator, name_span)) - .collect(), - span, - }, - Value::Stream { stream, span } => Value::Stream { - stream: stream - .flat_map(move |x| split_row_helper(&x, &separator, name_span)) - .into_value_stream(), - span, - }, - v => { - let v_span = v.span(); - if v.as_string().is_ok() { - Value::List { - vals: split_row_helper(&v, &separator, name_span), - span: v_span, - } - } else { - Value::Error { - error: ShellError::PipelineMismatch { - expected: Type::String, - expected_span: call.head, - origin: v.span(), - }, - } - } - } - }) + Ok(input.flat_map(name_span, move |x| { + split_row_helper(&x, &separator, name_span) + })) } fn split_row_helper(v: &Value, separator: &Spanned, name: Span) -> Vec { diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index afc1f90161..b003be1678 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -364,6 +364,73 @@ impl Value { _ => vec![], } } + + pub fn map(self, span: Span, mut f: F) -> Value + where + Self: Sized, + F: FnMut(Self) -> Value + 'static, + { + match self { + Value::List { vals, .. } => Value::List { + vals: vals.into_iter().map(f).collect(), + span, + }, + Value::Stream { stream, .. } => Value::Stream { + stream: stream.map(f).into_value_stream(), + span, + }, + v => { + if v.as_string().is_ok() { + Value::List { + vals: vec![f(v)], + span, + } + } else { + Value::Error { + error: ShellError::PipelineMismatch { + expected: Type::String, + expected_span: span, + origin: v.span(), + }, + } + } + } + } + } + + pub fn flat_map(self, span: Span, mut f: F) -> Value + where + Self: Sized, + U: IntoIterator, + F: FnMut(Self) -> U + 'static, + { + match self { + Value::List { vals, .. } => Value::List { + vals: vals.into_iter().map(f).flatten().collect(), + span, + }, + Value::Stream { stream, .. } => Value::Stream { + stream: stream.map(f).flatten().into_value_stream(), + span, + }, + v => { + if v.as_string().is_ok() { + Value::List { + vals: f(v).into_iter().collect(), + span, + } + } else { + Value::Error { + error: ShellError::PipelineMismatch { + expected: Type::String, + expected_span: span, + origin: v.span(), + }, + } + } + } + } + } } impl PartialEq for Value {