nu_command/strings/base/
base32.rs1use data_encoding::Encoding;
2
3use nu_engine::command_prelude::*;
4
5const EXTRA_USAGE: &str = r"The default alphabet is taken from RFC 4648, section 6.
6
7Note this command will collect stream input.";
8
9#[derive(Clone)]
10pub struct DecodeBase32;
11
12impl Command for DecodeBase32 {
13 fn name(&self) -> &str {
14 "decode base32"
15 }
16
17 fn signature(&self) -> Signature {
18 Signature::build("decode base32")
19 .input_output_types(vec![(Type::String, Type::Binary)])
20 .allow_variants_without_examples(true)
21 .switch("nopad", "Do not pad the output.", None)
22 .category(Category::Formats)
23 }
24
25 fn description(&self) -> &str {
26 "Decode a Base32 value."
27 }
28
29 fn extra_description(&self) -> &str {
30 EXTRA_USAGE
31 }
32
33 fn examples(&self) -> Vec<Example> {
34 vec![
35 Example {
36 description: "Decode arbitrary binary data",
37 example: r#""AEBAGBAF" | decode base32"#,
38 result: Some(Value::test_binary(vec![1, 2, 3, 4, 5])),
39 },
40 Example {
41 description: "Decode an encoded string",
42 example: r#""NBUQ====" | decode base32 | decode"#,
43 result: None,
44 },
45 Example {
46 description: "Parse a string without padding",
47 example: r#""NBUQ" | decode base32 --nopad"#,
48 result: Some(Value::test_binary(vec![0x68, 0x69])),
49 },
50 ]
51 }
52
53 fn is_const(&self) -> bool {
54 true
55 }
56
57 fn run(
58 &self,
59 engine_state: &EngineState,
60 stack: &mut Stack,
61 call: &Call,
62 input: PipelineData,
63 ) -> Result<PipelineData, ShellError> {
64 let encoding = if call.has_flag(engine_state, stack, "nopad")? {
65 data_encoding::BASE32_NOPAD
66 } else {
67 data_encoding::BASE32
68 };
69 super::decode(encoding, call.span(), input)
70 }
71
72 fn run_const(
73 &self,
74 working_set: &StateWorkingSet,
75 call: &Call,
76 input: PipelineData,
77 ) -> Result<PipelineData, ShellError> {
78 let encoding = if call.has_flag_const(working_set, "nopad")? {
79 data_encoding::BASE32_NOPAD
80 } else {
81 data_encoding::BASE32
82 };
83 super::decode(encoding, call.span(), input)
84 }
85}
86
87#[derive(Clone)]
88pub struct EncodeBase32;
89
90impl Command for EncodeBase32 {
91 fn name(&self) -> &str {
92 "encode base32"
93 }
94
95 fn signature(&self) -> Signature {
96 Signature::build("encode base32")
97 .input_output_types(vec![
98 (Type::String, Type::String),
99 (Type::Binary, Type::String),
100 ])
101 .switch("nopad", "Don't accept padding.", None)
102 .category(Category::Formats)
103 }
104
105 fn description(&self) -> &str {
106 "Encode a string or binary value using Base32."
107 }
108
109 fn extra_description(&self) -> &str {
110 EXTRA_USAGE
111 }
112
113 fn examples(&self) -> Vec<Example> {
114 vec![
115 Example {
116 description: "Encode a binary value",
117 example: r#"0x[01 02 10] | encode base32"#,
118 result: Some(Value::test_string("AEBBA===")),
119 },
120 Example {
121 description: "Encode a string",
122 example: r#""hello there" | encode base32"#,
123 result: Some(Value::test_string("NBSWY3DPEB2GQZLSMU======")),
124 },
125 Example {
126 description: "Don't apply padding to the output",
127 example: r#""hi" | encode base32 --nopad"#,
128 result: Some(Value::test_string("NBUQ")),
129 },
130 ]
131 }
132
133 fn is_const(&self) -> bool {
134 true
135 }
136
137 fn run(
138 &self,
139 engine_state: &EngineState,
140 stack: &mut Stack,
141 call: &Call,
142 input: PipelineData,
143 ) -> Result<PipelineData, ShellError> {
144 let encoding = if call.has_flag(engine_state, stack, "nopad")? {
145 data_encoding::BASE32_NOPAD
146 } else {
147 data_encoding::BASE32
148 };
149 super::encode(encoding, call.span(), input)
150 }
151
152 fn run_const(
153 &self,
154 working_set: &StateWorkingSet,
155 call: &Call,
156 input: PipelineData,
157 ) -> Result<PipelineData, ShellError> {
158 let encoding = if call.has_flag_const(working_set, "nopad")? {
159 data_encoding::BASE32_NOPAD
160 } else {
161 data_encoding::BASE32
162 };
163 super::encode(encoding, call.span(), input)
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 #[test]
172 fn test_examples_decode() {
173 crate::test_examples(DecodeBase32)
174 }
175
176 #[test]
177 fn test_examples_encode() {
178 crate::test_examples(EncodeBase32)
179 }
180}