Initial commit

This commit is contained in:
Andrej Kolchin 2024-07-23 16:37:54 +03:00
parent 366e52b76d
commit ec9089ebc5
7 changed files with 255 additions and 0 deletions

7
Cargo.lock generated
View File

@ -1147,6 +1147,12 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "data-encoding"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
[[package]]
name = "deranged"
version = "0.3.11"
@ -3044,6 +3050,7 @@ dependencies = [
"chrono-tz 0.8.6",
"crossterm",
"csv",
"data-encoding",
"deunicode",
"dialoguer",
"digest",

View File

@ -102,6 +102,7 @@ v_htmlescape = { workspace = true }
wax = { workspace = true }
which = { workspace = true }
unicode-width = { workspace = true }
data-encoding = { version = "2.6.0", features = ["alloc"] }
[target.'cfg(windows)'.dependencies]
winreg = { workspace = true }

View File

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

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,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,88 @@
use nu_protocol::{PipelineData, ShellError, Span, Value};
mod decode;
mod encode;
pub use decode::DecodeBase;
pub use encode::EncodeBase;
pub fn encoding(
name: &str,
val_span: Span,
call_span: Span,
) -> Result<data_encoding::Encoding, ShellError> {
match name {
"base32" => Ok(data_encoding::BASE32),
"base32hex" => Ok(data_encoding::BASE32HEX),
"base32hex_nopad" => Ok(data_encoding::BASE32HEX_NOPAD),
"base32_dnscurve" => Ok(data_encoding::BASE32_DNSCURVE),
"base32_dnssec" => Ok(data_encoding::BASE32_DNSSEC),
"base32_nopad" => Ok(data_encoding::BASE32_NOPAD),
"base64" => Ok(data_encoding::BASE64),
"base64url" => Ok(data_encoding::BASE64URL),
"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,
}),
}
}
pub fn get_string(input: PipelineData, call_span: Span) -> Result<(String, Span), ShellError> {
match input {
PipelineData::Value(val, ..) => {
let span = val.span();
match val {
Value::String { val, .. } => Ok((val, span)),
_ => {
todo!("Invalid type")
}
}
}
PipelineData::ListStream(..) => {
todo!()
}
PipelineData::ByteStream(stream, ..) => {
let span = stream.span();
Ok((stream.into_string()?, span))
}
PipelineData::Empty => {
todo!("Can't have empty data");
}
}
}
pub fn get_binary(input: PipelineData, call_span: Span) -> Result<(Vec<u8>, Span), ShellError> {
match input {
PipelineData::Value(val, ..) => {
let span = val.span();
match val {
Value::Binary { val, .. } => Ok((val, span)),
Value::String { val, .. } => Ok((val.into_bytes(), span)),
_ => {
todo!("Invalid type")
}
}
}
PipelineData::ListStream(..) => {
todo!()
}
PipelineData::ByteStream(stream, ..) => {
let span = stream.span();
Ok((stream.into_bytes()?, span))
}
PipelineData::Empty => {
todo!("Can't have empty data");
}
}
}

View File

@ -1,3 +1,4 @@
mod base;
mod char_;
mod detect_columns;
mod encode_decode;
@ -7,6 +8,7 @@ mod parse;
mod split;
mod str_;
pub use base::{DecodeBase, EncodeBase};
pub use char_::Char;
pub use detect_columns::*;
pub use encode_decode::*;