summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWindSoilder <WindSoilder@outlook.com>2022-07-05 19:42:01 +0800
committerGitHub <noreply@github.com>2022-07-05 06:42:01 -0500
commit390d06d4e7383d9fee814713bda8d1aaca858c5a (patch)
tree396996bda56715f59944a7d21adf95423436ef39
parent89acbda8772522bafb0c7e5ca072c946e73bb3d3 (diff)
add bytes starts-with command (#5950)0.65.0
* refactor operate, make it generic * refactor operate, add starts with command * add comment * remove useless file
-rw-r--r--crates/nu-command/src/bytes/length.rs66
-rw-r--r--crates/nu-command/src/bytes/mod.rs74
-rw-r--r--crates/nu-command/src/bytes/starts_with.rs122
-rw-r--r--crates/nu-command/src/default_context.rs3
4 files changed, 221 insertions, 44 deletions
diff --git a/crates/nu-command/src/bytes/length.rs b/crates/nu-command/src/bytes/length.rs
index 4094abaff..9e8dbb162 100644
--- a/crates/nu-command/src/bytes/length.rs
+++ b/crates/nu-command/src/bytes/length.rs
@@ -1,3 +1,4 @@
+use super::{operate, BytesArgument};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath;
@@ -8,6 +9,16 @@ use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShap
#[derive(Clone)]
pub struct BytesLen;
+struct Arguments {
+ column_paths: Option<Vec<CellPath>>,
+}
+
+impl BytesArgument for Arguments {
+ fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
+ self.column_paths.take()
+ }
+}
+
impl Command for BytesLen {
fn name(&self) -> &str {
"bytes length"
@@ -38,7 +49,14 @@ impl Command for BytesLen {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
- operate(engine_state, stack, call, input)
+ let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
+ let column_paths = if column_paths.is_empty() {
+ None
+ } else {
+ Some(column_paths)
+ };
+ let arg = Arguments { column_paths };
+ operate(length, arg, input, call.head, engine_state.ctrlc.clone())
}
fn examples(&self) -> Vec<Example> {
@@ -60,48 +78,10 @@ impl Command for BytesLen {
}
}
-fn operate(
- engine_state: &EngineState,
- stack: &mut Stack,
- call: &Call,
- input: PipelineData,
-) -> Result<PipelineData, ShellError> {
- let head = call.head;
- let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
- if column_paths.is_empty() {
- input.map(move |v| action(&v, head), engine_state.ctrlc.clone())
- } else {
- input.map(
- move |mut v| {
- for path in &column_paths {
- let r =
- v.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
- if let Err(error) = r {
- return Value::Error { error };
- }
- }
- v
- },
- engine_state.ctrlc.clone(),
- )
- }
-}
-
-fn action(input: &Value, head: Span) -> Value {
- match input {
- Value::Binary { val, .. } => Value::Int {
- val: val.len() as i64,
- span: head,
- },
- other => Value::Error {
- error: ShellError::UnsupportedInput(
- format!(
- "Input's type is {}. This command only works with bytes.",
- other.get_type()
- ),
- head,
- ),
- },
+fn length(input: &[u8], _arg: &Arguments, span: Span) -> Value {
+ Value::Int {
+ val: input.len() as i64,
+ span,
}
}
diff --git a/crates/nu-command/src/bytes/mod.rs b/crates/nu-command/src/bytes/mod.rs
index 0eda47d6f..30cdd039e 100644
--- a/crates/nu-command/src/bytes/mod.rs
+++ b/crates/nu-command/src/bytes/mod.rs
@@ -1,3 +1,77 @@
mod length;
+mod starts_with;
+use nu_protocol::ast::CellPath;
+use nu_protocol::{PipelineData, ShellError, Span, Value};
+use std::sync::atomic::AtomicBool;
+use std::sync::Arc;
pub use length::BytesLen;
+pub use starts_with::BytesStartsWith;
+
+trait BytesArgument {
+ fn take_column_paths(&mut self) -> Option<Vec<CellPath>>;
+}
+
+/// map input pipeline data, for each elements, if it's Binary, invoke relative `cmd` with `arg`.
+fn operate<C, A>(
+ cmd: C,
+ mut arg: A,
+ input: PipelineData,
+ span: Span,
+ ctrlc: Option<Arc<AtomicBool>>,
+) -> Result<PipelineData, ShellError>
+where
+ A: BytesArgument + Send + Sync + 'static,
+ C: Fn(&[u8], &A, Span) -> Value + Send + Sync + 'static + Clone + Copy,
+{
+ match arg.take_column_paths() {
+ None => input.map(
+ move |v| match v {
+ Value::Binary {
+ val,
+ span: val_span,
+ } => cmd(&val, &arg, val_span),
+ other => Value::Error {
+ error: ShellError::UnsupportedInput(
+ format!(
+ "Input's type is {}. This command only works with bytes.",
+ other.get_type()
+ ),
+ span,
+ ),
+ },
+ },
+ ctrlc,
+ ),
+ Some(column_paths) => {
+ let arg = Arc::new(arg);
+ input.map(
+ move |mut v| {
+ for path in &column_paths {
+ let opt = arg.clone();
+ let r = v.update_cell_path(
+ &path.members,
+ Box::new(move |old| {
+ match old {
+ Value::Binary {val, span: val_span} => cmd(val, &opt, *val_span),
+ other => Value::Error {
+ error: ShellError::UnsupportedInput(
+ format!(
+ "Input's type is {}. This command only works with bytes.",
+ other.get_type()
+ ),
+ span,
+ ),
+ }}}),
+ );
+ if let Err(error) = r {
+ return Value::Error { error };
+ }
+ }
+ v
+ },
+ ctrlc,
+ )
+ }
+ }
+}
diff --git a/crates/nu-command/src/bytes/starts_with.rs b/crates/nu-command/src/bytes/starts_with.rs
new file mode 100644
index 000000000..a022530a2
--- /dev/null
+++ b/crates/nu-command/src/bytes/starts_with.rs
@@ -0,0 +1,122 @@
+use super::{operate, BytesArgument};
+use nu_engine::CallExt;
+use nu_protocol::ast::Call;
+use nu_protocol::ast::CellPath;
+use nu_protocol::engine::{Command, EngineState, Stack};
+use nu_protocol::Category;
+use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value};
+
+struct Arguments {
+ pattern: Vec<u8>,
+ column_paths: Option<Vec<CellPath>>,
+}
+
+impl BytesArgument for Arguments {
+ fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
+ self.column_paths.take()
+ }
+}
+
+#[derive(Clone)]
+
+pub struct BytesStartsWith;
+
+impl Command for BytesStartsWith {
+ fn name(&self) -> &str {
+ "bytes starts-with"
+ }
+
+ fn signature(&self) -> Signature {
+ Signature::build("bytes starts-with")
+ .required("pattern", SyntaxShape::Binary, "the pattern to match")
+ .rest(
+ "rest",
+ SyntaxShape::CellPath,
+ "optionally matches prefix of text by column paths",
+ )
+ .category(Category::Bytes)
+ }
+
+ fn usage(&self) -> &str {
+ "Check if bytes starts with a pattern"
+ }
+
+ fn search_terms(&self) -> Vec<&str> {
+ vec!["pattern", "match", "find", "search"]
+ }
+
+ fn run(
+ &self,
+ engine_state: &EngineState,
+ stack: &mut Stack,
+ call: &Call,
+ input: PipelineData,
+ ) -> Result<PipelineData, ShellError> {
+ let pattern: Vec<u8> = call.req(engine_state, stack, 0)?;
+ let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
+ let column_paths = if column_paths.is_empty() {
+ None
+ } else {
+ Some(column_paths)
+ };
+ let arg = Arguments {
+ pattern,
+ column_paths,
+ };
+ operate(
+ starts_with,
+ arg,
+ input,
+ call.head,
+ engine_state.ctrlc.clone(),
+ )
+ }
+
+ fn examples(&self) -> Vec<Example> {
+ vec![
+ Example {
+ description: "Checks if binary starts with `0x[1F FF AA]`",
+ example: "0x[1F FF AA AA] | bytes starts-with 0x[1F FF AA]",
+ result: Some(Value::Bool {
+ val: true,
+ span: Span::test_data(),
+ }),
+ },
+ Example {
+ description: "Checks if binary starts with `0x[1F]`",
+ example: "0x[1F FF AA AA] | bytes starts-with 0x[1F]",
+ result: Some(Value::Bool {
+ val: true,
+ span: Span::test_data(),
+ }),
+ },
+ Example {
+ description: "Checks if binary starts with `0x[1F]`",
+ example: "0x[1F FF AA AA] | bytes starts-with 0x[11]",
+ result: Some(Value::Bool {
+ val: false,
+ span: Span::test_data(),
+ }),
+ },
+ ]
+ }
+}
+
+fn starts_with(input: &[u8], Arguments { pattern, .. }: &Arguments, span: Span) -> Value {
+ Value::Bool {
+ val: input.starts_with(pattern),
+ span,
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_examples() {
+ use crate::test_examples;
+
+ test_examples(BytesStartsWith {})
+ }
+}
diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs
index b3f3418ba..604ba726c 100644
--- a/crates/nu-command/src/default_context.rs
+++ b/crates/nu-command/src/default_context.rs
@@ -209,7 +209,8 @@ pub fn create_default_context(cwd: impl AsRef<Path>) -> EngineState {
// Bytes
bind_command! {
- BytesLen
+ BytesLen,
+ BytesStartsWith
}
// FileSystem