Mid-refactor

This commit is contained in:
Andrej Kolchin 2024-07-23 19:32:07 +03:00
parent ec9089ebc5
commit 51b0f97fda
11 changed files with 547 additions and 40 deletions

View File

@ -179,8 +179,6 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
Char, Char,
Decode, Decode,
Encode, Encode,
EncodeBase,
DecodeBase,
DecodeBase64, DecodeBase64,
EncodeBase64, EncodeBase64,
DetectColumns, DetectColumns,

View File

@ -0,0 +1,62 @@
use data_encoding::Encoding;
use nu_engine::command_prelude::*;
pub struct Base32Config {
lower: bool,
lower_span: Option<Span>,
nopad: bool,
nopad_span: Option<Span>,
dnscurve: bool,
dnscurve_span: Option<Span>,
dnssec: bool,
dnssec_span: Option<Span>,
}
impl Base32Config {
pub fn new(engine_state: &EngineState, stack: &mut Stack, call: &Call) -> Self {
Base32Config {
lower: call.get_flag(engine_state, stack, "lower"),
lower_span: call.get_flag_span(stack, "lower"),
nopad: call.get_flag(engine_state, stack, "nopad"),
nopad_span: call.get_flag_span(stack, "nopad"),
dnscurve: call.get_flag(engine_state, stack, "dnscurve"),
dnscurve_span: call.get_flag_span(stack, "dnscurve"),
dnssec: call.get_flag(engine_state, stack, "dnssec"),
dnssec_span: call.get_flag_span(stack, "dnssec"),
}
}
}
fn base32_encoding(config: Base32Config) -> Result<Encoding, ShellError> {
if let Some(dnscurve_span) = config.dnscurve_span {
if let Some(lower_span) = config.lower_span {
return Err(ShellError::IncompatibleParameters {
left_message: "Inapplicable to DNSCURVE".to_string(),
left_span: lower_span,
right_message: "DNSCURVE must be used standalone".to_string(),
right_span: dnscurve_span,
});
}
if let Some(nopad_span) = config.nopad_span {
return Err(ShellError::IncompatibleParameters {
left_message: "Inapplicable to DNSCURVE".to_string(),
left_span: nopad_span,
right_message: "DNSCURVE must be used standalone".to_string(),
right_span: dnscurve_span,
});
}
if let Some(dnssec) = config.dnssec_span {
return Err(ShellError::IncompatibleParameters {
left_message: "Inapplicable to DNSCURVE".to_string(),
left_span: nopad_span,
right_message: "DNSCURVE must be used standalone".to_string(),
right_span: dnscurve_span,
});
}
return Ok(data_encoding::BASE32_DNSCURVE);
}
todo!()
}

View File

@ -0,0 +1,66 @@
use nu_engine::command_prelude::*;
#[derive(Clone)]
pub struct DecodeBase32;
impl Command for DecodeBase32 {
fn name(&self) -> &str {
"decode base32"
}
fn signature(&self) -> Signature {
Signature::build("decode base32")
.input_output_types(vec![(Type::String, Type::Binary)])
.allow_variants_without_examples(true)
.switch("lower", "Use a lowercase version of Base32.", None)
.switch("nopad", "Do not pad the output.", None)
.switch("dnscurve", "Use DNSCURVE Base32 variant.", None)
.switch("dnssec", "Use DNSSEC Base32 variant.", None)
.category(Category::Formats)
}
fn usage(&self) -> &str {
"Decode a value."
}
fn extra_usage(&self) -> &str {
"TODO"
}
fn examples(&self) -> Vec<Example> {
vec![]
}
fn is_const(&self) -> bool {
true
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
todo!()
}
fn run_const(
&self,
working_set: &StateWorkingSet,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
todo!()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_examples() {
crate::test_examples(DecodeBase32)
}
}

View File

@ -0,0 +1,67 @@
use nu_engine::command_prelude::*;
#[derive(Clone)]
pub struct DecodeBase;
impl Command for DecodeBase {
fn name(&self) -> &str {
"decode base"
}
fn signature(&self) -> Signature {
Signature::build("decode base")
.input_output_types(vec![(Type::String, Type::Binary)])
.allow_variants_without_examples(true)
.required("encoding", SyntaxShape::String, "encoding to use")
.category(Category::Formats)
}
fn usage(&self) -> &str {
"Decode a value."
}
fn extra_usage(&self) -> &str {
"TODO"
}
fn examples(&self) -> Vec<Example> {
vec![]
}
fn is_const(&self) -> bool {
true
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let name: String = call.req(engine_state, stack, 0)?;
decode(&name, call.span(), input)
}
fn run_const(
&self,
working_set: &StateWorkingSet,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let name: String = call.req_const(working_set, 0)?;
decode(&name, call.span(), input)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_examples() {
crate::test_examples(DecodeBase)
}
}

View File

@ -0,0 +1,76 @@
use nu_engine::command_prelude::*;
#[derive(Clone)]
pub struct DecodeBase;
impl Command for DecodeBase {
fn name(&self) -> &str {
"decode base"
}
fn signature(&self) -> Signature {
Signature::build("decode base")
.input_output_types(vec![(Type::String, Type::Binary)])
.allow_variants_without_examples(true)
.required("encoding", SyntaxShape::String, "encoding to use")
.category(Category::Formats)
}
fn usage(&self) -> &str {
"Decode a value."
}
fn extra_usage(&self) -> &str {
"TODO"
}
fn examples(&self) -> Vec<Example> {
vec![]
}
fn is_const(&self) -> bool {
true
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let name: String = call.req(engine_state, stack, 0)?;
decode(&name, call.span(), input)
}
fn run_const(
&self,
working_set: &StateWorkingSet,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let name: String = call.req_const(working_set, 0)?;
decode(&name, call.span(), input)
}
}
fn decode(name: &str, call_span: Span, input: PipelineData) -> Result<PipelineData, ShellError> {
let encoding = super::encoding(&name, call_span, call_span)?;
let metadata = input.metadata();
let (input_str, input_span) = super::get_string(input, call_span)?;
let output = encoding.decode(input_str.as_bytes()).unwrap();
Ok(Value::binary(output, call_span).into_pipeline_data_with_metadata(metadata))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_examples() {
crate::test_examples(DecodeBase)
}
}

View File

@ -0,0 +1,70 @@
use nu_engine::command_prelude::*;
#[derive(Clone)]
pub struct EncodeBase;
impl Command for EncodeBase {
fn name(&self) -> &str {
"encode base"
}
fn signature(&self) -> Signature {
Signature::build("encode base")
.input_output_types(vec![
(Type::String, Type::String),
(Type::Binary, Type::String),
])
.allow_variants_without_examples(true)
.required("encoding", SyntaxShape::String, "encoding to use")
.category(Category::Formats)
}
fn usage(&self) -> &str {
"Encode a value."
}
fn extra_usage(&self) -> &str {
"TODO"
}
fn examples(&self) -> Vec<Example> {
vec![]
}
fn is_const(&self) -> bool {
true
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let name: String = call.req(engine_state, stack, 0)?;
encode(&name, call.span(), input)
}
fn run_const(
&self,
working_set: &StateWorkingSet,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let name: String = call.req_const(working_set, 0)?;
encode(&name, call.span(), input)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_examples() {
crate::test_examples(EncodeBase)
}
}

View File

@ -0,0 +1,79 @@
use nu_engine::command_prelude::*;
#[derive(Clone)]
pub struct EncodeBase;
impl Command for EncodeBase {
fn name(&self) -> &str {
"encode base"
}
fn signature(&self) -> Signature {
Signature::build("encode base")
.input_output_types(vec![
(Type::String, Type::String),
(Type::Binary, Type::String),
])
.allow_variants_without_examples(true)
.required("encoding", SyntaxShape::String, "encoding to use")
.category(Category::Formats)
}
fn usage(&self) -> &str {
"Encode a value."
}
fn extra_usage(&self) -> &str {
"TODO"
}
fn examples(&self) -> Vec<Example> {
vec![]
}
fn is_const(&self) -> bool {
true
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let name: String = call.req(engine_state, stack, 0)?;
encode(&name, call.span(), input)
}
fn run_const(
&self,
working_set: &StateWorkingSet,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let name: String = call.req_const(working_set, 0)?;
encode(&name, call.span(), input)
}
}
fn encode(name: &str, call_span: Span, input: PipelineData) -> Result<PipelineData, ShellError> {
let encoding = super::encoding(name, call_span, call_span)?;
let metadata = input.metadata();
let (input_bytes, input_span) = super::get_binary(input, call_span)?;
let output = encoding.encode(&input_bytes);
Ok(Value::string(output, call_span).into_pipeline_data_with_metadata(metadata))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_examples() {
crate::test_examples(EncodeBase)
}
}

View File

@ -0,0 +1,79 @@
use nu_engine::command_prelude::*;
#[derive(Clone)]
pub struct EncodeBase;
impl Command for EncodeBase {
fn name(&self) -> &str {
"encode base"
}
fn signature(&self) -> Signature {
Signature::build("encode base")
.input_output_types(vec![
(Type::String, Type::String),
(Type::Binary, Type::String),
])
.allow_variants_without_examples(true)
.required("encoding", SyntaxShape::String, "encoding to use")
.category(Category::Formats)
}
fn usage(&self) -> &str {
"Encode a value."
}
fn extra_usage(&self) -> &str {
"TODO"
}
fn examples(&self) -> Vec<Example> {
vec![]
}
fn is_const(&self) -> bool {
true
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let name: String = call.req(engine_state, stack, 0)?;
encode(&name, call.span(), input)
}
fn run_const(
&self,
working_set: &StateWorkingSet,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let name: String = call.req_const(working_set, 0)?;
encode(&name, call.span(), input)
}
}
fn encode(name: &str, call_span: Span, input: PipelineData) -> Result<PipelineData, ShellError> {
let encoding = super::encoding(name, call_span, call_span)?;
let metadata = input.metadata();
let (input_bytes, input_span) = super::get_binary(input, call_span)?;
let output = encoding.encode(&input_bytes);
Ok(Value::string(output, call_span).into_pipeline_data_with_metadata(metadata))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_examples() {
crate::test_examples(EncodeBase)
}
}

View File

@ -1,42 +1,52 @@
use nu_protocol::{PipelineData, ShellError, Span, Value}; use data_encoding::Encoding;
mod decode; use nu_protocol::{IntoPipelineData, PipelineData, ShellError, Span, Value};
mod encode;
pub use decode::DecodeBase; mod decode_base32;
pub use encode::EncodeBase; mod decode_base32hex;
mod decode_base64;
mod decode_hex;
mod encode_base32;
mod encode_base32hex;
mod encode_base64;
mod encode_hex;
pub fn encoding( mod base32;
name: &str,
val_span: Span, fn decode(
encoding: Encoding,
call_span: Span, call_span: Span,
) -> Result<data_encoding::Encoding, ShellError> { input: PipelineData,
match name { ) -> Result<PipelineData, ShellError> {
"base32" => Ok(data_encoding::BASE32), let metadata = input.metadata();
"base32hex" => Ok(data_encoding::BASE32HEX), let (input_str, input_span) = get_string(input, call_span)?;
"base32hex_nopad" => Ok(data_encoding::BASE32HEX_NOPAD), let output = match encoding.decode(input_str.as_bytes()) {
"base32_dnscurve" => Ok(data_encoding::BASE32_DNSCURVE), Ok(output) => output,
"base32_dnssec" => Ok(data_encoding::BASE32_DNSSEC), Err(err) => {
"base32_nopad" => Ok(data_encoding::BASE32_NOPAD), return Err(ShellError::IncorrectValue {
"base64" => Ok(data_encoding::BASE64), msg: err.to_string(),
"base64url" => Ok(data_encoding::BASE64URL), val_span: input_span,
"base64url_nopad" => Ok(data_encoding::BASE64URL_NOPAD),
"base64_mime" => Ok(data_encoding::BASE64_MIME),
"base64_mime_permissive" => Ok(data_encoding::BASE64_MIME_PERMISSIVE),
"base64_nopad" => Ok(data_encoding::BASE64_NOPAD),
"hexlower" => Ok(data_encoding::HEXLOWER),
"hexlower_permissive" => Ok(data_encoding::HEXLOWER_PERMISSIVE),
"hexupper" => Ok(data_encoding::HEXUPPER),
"hexupper_permissive" => Ok(data_encoding::HEXUPPER_PERMISSIVE),
_ => Err(ShellError::IncorrectValue {
msg: format!("Encoding '{name}' not found"),
val_span,
call_span, call_span,
}), });
} }
};
Ok(Value::binary(output, call_span).into_pipeline_data_with_metadata(metadata))
} }
pub fn get_string(input: PipelineData, call_span: Span) -> Result<(String, Span), ShellError> { fn encode(
encoding: Encoding,
call_span: Span,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let metadata = input.metadata();
let (input_bytes, _) = get_binary(input, call_span)?;
let output = encoding.encode(&input_bytes);
Ok(Value::string(output, call_span).into_pipeline_data_with_metadata(metadata))
}
fn get_string(input: PipelineData, call_span: Span) -> Result<(String, Span), ShellError> {
match input { match input {
PipelineData::Value(val, ..) => { PipelineData::Value(val, ..) => {
let span = val.span(); let span = val.span();
@ -55,13 +65,13 @@ pub fn get_string(input: PipelineData, call_span: Span) -> Result<(String, Span)
let span = stream.span(); let span = stream.span();
Ok((stream.into_string()?, span)) Ok((stream.into_string()?, span))
} }
PipelineData::Empty => { PipelineData::Empty => Err(ShellError::PipelineEmpty {
todo!("Can't have empty data"); dst_span: call_span,
} }),
} }
} }
pub fn get_binary(input: PipelineData, call_span: Span) -> Result<(Vec<u8>, Span), ShellError> { fn get_binary(input: PipelineData, call_span: Span) -> Result<(Vec<u8>, Span), ShellError> {
match input { match input {
PipelineData::Value(val, ..) => { PipelineData::Value(val, ..) => {
let span = val.span(); let span = val.span();