rqjs_ext/modules/encoding/
encoder.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3use hex_simd::AsciiCase;
4
5macro_rules! encoder_enum {
6    (
7        $(#[$attr:meta])*
8        pub enum $enum_name:ident {
9            $($variant:ident),* $(,)?
10        }
11    ) => {
12        $(#[$attr])*
13        pub enum $enum_name {
14            $($variant),*
15        }
16
17        impl $enum_name {
18            #[allow(clippy::should_implement_trait)]
19            pub fn from_str(encoding: &str) -> Result<Self, String> {
20
21                let encoding:String = encoding.chars()
22                    .enumerate()
23                    .map(|(i, c)| {
24                        if i == 0 {
25                            c.to_ascii_uppercase()
26                        } else {
27                            c.to_ascii_lowercase()
28                        }
29                    })
30                    .filter(|&c| c != '-' && c != '_')
31                    .collect();
32
33                match encoding.as_str() {
34                    $(
35                        stringify!($variant) => Ok(Self::$variant),
36                    )*
37                    _ => Err(format!("Unsupported encoding: {}", encoding)),
38                }
39            }
40        }
41    };
42}
43
44encoder_enum! {
45    #[derive(Debug)]
46    pub enum Encoder {
47        Hex,
48        Base64,
49        Utf8,
50        Iso88591,
51    }
52}
53
54impl Encoder {
55    pub fn encode_to_string(&self, bytes: &[u8]) -> Result<String, String> {
56        match self {
57            Self::Hex => Ok(bytes_to_hex_string(bytes)),
58            Self::Base64 => Ok(bytes_to_b64_string(bytes)),
59            Self::Utf8 | Self::Iso88591 => Ok(bytes_to_string(bytes)),
60        }
61    }
62
63    #[allow(dead_code)]
64    pub fn encode(&self, bytes: &[u8]) -> Result<Vec<u8>, String> {
65        match self {
66            Self::Hex => Ok(bytes_to_hex(bytes)),
67            Self::Base64 => Ok(bytes_to_b64(bytes)),
68            Self::Utf8 | Self::Iso88591 => Ok(bytes.to_vec()),
69        }
70    }
71
72    pub fn decode(&self, bytes: Vec<u8>) -> Result<Vec<u8>, String> {
73        match self {
74            Self::Hex => bytes_from_hex(&bytes),
75            Self::Base64 => bytes_from_b64(&bytes),
76            Self::Utf8 | Self::Iso88591 => Ok(bytes),
77        }
78    }
79
80    #[allow(dead_code)]
81    pub fn decode_from_string(&self, string: String) -> Result<Vec<u8>, String> {
82        match self {
83            Self::Hex => bytes_from_hex(string.as_bytes()),
84            Self::Base64 => bytes_from_b64(string.as_bytes()),
85            Self::Utf8 | Self::Iso88591 => Ok(string.into_bytes()),
86        }
87    }
88}
89
90pub fn bytes_to_hex(bytes: &[u8]) -> Vec<u8> {
91    hex_simd::encode_type(bytes, AsciiCase::Lower)
92}
93
94pub fn bytes_from_hex(hex_bytes: &[u8]) -> Result<Vec<u8>, String> {
95    hex_simd::decode_to_vec(hex_bytes).map_err(|err| err.to_string())
96}
97
98pub fn bytes_to_b64_string(bytes: &[u8]) -> String {
99    base64_simd::STANDARD.encode_to_string(bytes)
100}
101
102pub fn bytes_from_b64(bytes: &[u8]) -> Result<Vec<u8>, String> {
103    base64_simd::forgiving_decode_to_vec(bytes).map_err(|e| e.to_string())
104}
105
106pub fn bytes_to_b64(bytes: &[u8]) -> Vec<u8> {
107    base64_simd::STANDARD.encode_type(bytes)
108}
109
110pub fn bytes_to_hex_string(bytes: &[u8]) -> String {
111    hex_simd::encode_to_string(bytes, AsciiCase::Lower)
112}
113
114pub fn bytes_to_string(bytes: &[u8]) -> String {
115    String::from_utf8_lossy(bytes).to_string()
116}