nu_command/strings/base/
base32hex.rs

1use nu_engine::command_prelude::*;
2
3const EXTRA_USAGE: &str = r"This command uses an alternative Base32 alphabet, defined in RFC 4648, section 7.
4
5Note this command will collect stream input.";
6
7#[derive(Clone)]
8pub struct DecodeBase32Hex;
9
10impl Command for DecodeBase32Hex {
11    fn name(&self) -> &str {
12        "decode base32hex"
13    }
14
15    fn signature(&self) -> Signature {
16        Signature::build("decode base32hex")
17            .input_output_types(vec![(Type::String, Type::Binary)])
18            .allow_variants_without_examples(true)
19            .switch("nopad", "Reject input with padding.", None)
20            .category(Category::Formats)
21    }
22
23    fn description(&self) -> &str {
24        "Encode a base32hex value."
25    }
26
27    fn extra_description(&self) -> &str {
28        EXTRA_USAGE
29    }
30
31    fn examples(&self) -> Vec<Example> {
32        vec![
33            Example {
34                description: "Decode arbitrary binary data",
35                example: r#""ATNAQ===" | decode base32hex"#,
36                result: Some(Value::test_binary(vec![0x57, 0x6E, 0xAD])),
37            },
38            Example {
39                description: "Decode an encoded string",
40                example: r#""D1KG====" | decode base32hex | decode"#,
41                result: None,
42            },
43            Example {
44                description: "Parse a string without padding",
45                example: r#""ATNAQ" | decode base32hex --nopad"#,
46                result: Some(Value::test_binary(vec![0x57, 0x6E, 0xAD])),
47            },
48        ]
49    }
50
51    fn is_const(&self) -> bool {
52        true
53    }
54
55    fn run(
56        &self,
57        engine_state: &EngineState,
58        stack: &mut Stack,
59        call: &Call,
60        input: PipelineData,
61    ) -> Result<PipelineData, ShellError> {
62        let encoding = if call.has_flag(engine_state, stack, "nopad")? {
63            data_encoding::BASE32HEX_NOPAD
64        } else {
65            data_encoding::BASE32HEX
66        };
67
68        super::decode(encoding, call.head, input)
69    }
70
71    fn run_const(
72        &self,
73        working_set: &StateWorkingSet,
74        call: &Call,
75        input: PipelineData,
76    ) -> Result<PipelineData, ShellError> {
77        let encoding = if call.has_flag_const(working_set, "nopad")? {
78            data_encoding::BASE32HEX_NOPAD
79        } else {
80            data_encoding::BASE32HEX
81        };
82
83        super::decode(encoding, call.head, input)
84    }
85}
86
87#[derive(Clone)]
88pub struct EncodeBase32Hex;
89
90impl Command for EncodeBase32Hex {
91    fn name(&self) -> &str {
92        "encode base32hex"
93    }
94
95    fn signature(&self) -> Signature {
96        Signature::build("encode base32hex")
97            .input_output_types(vec![
98                (Type::String, Type::String),
99                (Type::Binary, Type::String),
100            ])
101            .switch("nopad", "Don't pad the output.", None)
102            .category(Category::Formats)
103    }
104
105    fn description(&self) -> &str {
106        "Encode a binary value or a string using base32hex."
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[57 6E AD] | encode base32hex"#,
118                result: Some(Value::test_string("ATNAQ===")),
119            },
120            Example {
121                description: "Encode a string",
122                example: r#""hello there" | encode base32hex"#,
123                result: Some(Value::test_string("D1IMOR3F41Q6GPBICK======")),
124            },
125            Example {
126                description: "Don't apply padding to the output",
127                example: r#""hello there" | encode base32hex --nopad"#,
128                result: Some(Value::test_string("D1IMOR3F41Q6GPBICK")),
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::BASE32HEX_NOPAD
146        } else {
147            data_encoding::BASE32HEX
148        };
149
150        super::encode(encoding, call.head, input)
151    }
152
153    fn run_const(
154        &self,
155        working_set: &StateWorkingSet,
156        call: &Call,
157        input: PipelineData,
158    ) -> Result<PipelineData, ShellError> {
159        let encoding = if call.has_flag_const(working_set, "nopad")? {
160            data_encoding::BASE32HEX_NOPAD
161        } else {
162            data_encoding::BASE32HEX
163        };
164
165        super::encode(encoding, call.head, input)
166    }
167}
168
169#[cfg(test)]
170mod tests {
171    use super::*;
172
173    #[test]
174    fn test_examples_decode() {
175        crate::test_examples(DecodeBase32Hex)
176    }
177    #[test]
178    fn test_examples_encode() {
179        crate::test_examples(EncodeBase32Hex)
180    }
181}