Skip to main content

nu_command/strings/base/
base32hex.rs

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