Skip to content

Commit 497bbf3

Browse files
committed
Merge branch 'release/0.1.0-beta'
2 parents 2ba69cb + 6584b20 commit 497bbf3

File tree

11 files changed

+384
-262
lines changed

11 files changed

+384
-262
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ In our daily project development, we frequently encounter situations where we ne
2626
## How to Install Wutong
2727
> [!NOTE]
2828
> During the test phase, Wutong does not provide installation methods. If you wish to experience it, please compile it yourself. Upon the release of the official version, Wutong will provide installation methods.
29+
> Version 0.1.0 we will launch Wutong at HomeBrew
2930
3031
---
3132

3233
## How to Use Wutong
3334
You can obtain detailed information by typing `wutong --help` in the command line.
34-
The general functions of Wutong are listed below (v0.1.0-alpha):
35+
The general functions of Wutong are listed below (v0.1.0-beta):
3536

3637
| Function | Description |
3738
|----------|--------------------------------------------------------------|

src/base/text/decode.rs

Lines changed: 39 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,55 @@
1-
pub fn base16_decode(input: &str) -> String {
2-
const BASE16_CHARS: &str = "0123456789abcdef";
3-
let mut char_to_index = [255; 256];
4-
for (i, c) in BASE16_CHARS.chars().enumerate() {
1+
pub fn base16_decode(input: &str) -> Result<String, String> {
2+
const BASE16_CHARS: &[u8] = b"0123456789abcdef";
3+
let mut char_to_index = [255u8; 256];
4+
for (i, &c) in BASE16_CHARS.iter().enumerate() {
55
char_to_index[c as usize] = (i % 16) as u8;
66
}
77

88
if input.len() % 2 != 0 {
9-
return String::from("Invalid base16 input: length is not even");
9+
return Err("Invalid base16 input: length is not even".to_string());
1010
}
1111

12-
let mut result = Vec::new();
12+
let mut result = Vec::with_capacity(input.len() / 2);
1313

1414
for (i, chunk) in input.as_bytes().chunks(2).enumerate() {
1515
if chunk.len() != 2 {
16-
return format!(
16+
return Err(format!(
1717
"Invalid base16 input: chunk at index {} has invalid length",
1818
i * 2
19-
);
19+
));
2020
}
2121

22-
let high_nibble = match char_to_index[chunk[0] as usize] {
23-
0..=15 => char_to_index[chunk[0] as usize],
24-
_ => {
25-
return format!(
26-
"Invalid base16 input: invalid character '{}' at index {}",
27-
char::from(chunk[0]),
28-
i * 2
29-
)
30-
}
31-
};
32-
33-
let low_nibble = match char_to_index[chunk[1] as usize] {
34-
0..=15 => char_to_index[chunk[1] as usize],
35-
_ => {
36-
return format!(
37-
"Invalid base16 input: invalid character '{}' at index {}",
38-
char::from(chunk[1]),
39-
i * 2 + 1
40-
)
41-
}
42-
};
22+
let high_nibble = char_to_index[chunk[0] as usize];
23+
if high_nibble == 255 {
24+
return Err(format!(
25+
"Invalid base16 input: invalid character '{}' at index {}",
26+
char::from(chunk[0]),
27+
i * 2
28+
));
29+
}
30+
31+
let low_nibble = char_to_index[chunk[1] as usize];
32+
if low_nibble == 255 {
33+
return Err(format!(
34+
"Invalid base16 input: invalid character '{}' at index {}",
35+
char::from(chunk[1]),
36+
i * 2 + 1
37+
));
38+
}
4339

4440
let byte = (high_nibble << 4) | low_nibble;
4541
result.push(byte);
4642
}
4743

48-
String::from_utf8(result)
49-
.unwrap_or_else(|_| String::from("Invalid UTF-8 sequence in decoded data"))
44+
String::from_utf8(result).map_err(|_| "Invalid UTF-8 sequence in decoded data".to_string())
5045
}
5146

52-
pub fn base64_decode(input: &str) -> String {
53-
const BASE64_CHARS: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
47+
pub fn base64_decode(input: &str) -> Result<String, String> {
48+
const BASE64_CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5449
let mut result = Vec::new();
5550

5651
if input.len() % 4 != 0 {
57-
return String::from("Invalid Base64 input.");
52+
return Err("Invalid Base64 input: length not divisible by 4".to_string());
5853
}
5954

6055
let chunks: Vec<_> = input.as_bytes().chunks(4).collect();
@@ -63,7 +58,7 @@ pub fn base64_decode(input: &str) -> String {
6358
let is_last_chunk = chunk_idx == chunks.len() - 1;
6459

6560
if chunk.len() != 4 {
66-
return String::from("Invalid Base64 input.");
61+
return Err("Invalid Base64 input: incomplete chunk".to_string());
6762
}
6863

6964
let mut values = [0u8; 4];
@@ -74,31 +69,27 @@ pub fn base64_decode(input: &str) -> String {
7469

7570
if c == '=' {
7671
if !is_last_chunk || i < 2 {
77-
return String::from("Invalid Base64 input.");
72+
return Err("Invalid Base64 padding".to_string());
7873
}
7974
pad_count += 1;
8075
values[i] = 0;
8176
} else {
82-
match BASE64_CHARS.find(c) {
77+
match BASE64_CHARS.iter().position(|&b| b == byte) {
8378
Some(idx) => values[i] = idx as u8,
84-
None => return String::from("Invalid Base64 input."),
85-
}
86-
87-
if is_last_chunk && pad_count > 0 {
88-
return String::from("Invalid Base64 input.");
79+
None => return Err(format!("Invalid Base64 character: '{}'", c)),
8980
}
9081
}
9182
}
9283

9384
if pad_count > 2 {
94-
return String::from("Invalid Base64 input.");
85+
return Err("Too many padding characters".to_string());
9586
}
9687

9788
if is_last_chunk {
9889
match pad_count {
99-
1 if chunk[3] != b'=' => return String::from("Invalid Base64 input."),
90+
1 if chunk[3] != b'=' => return Err("Invalid padding position".to_string()),
10091
2 if chunk[2] != b'=' || chunk[3] != b'=' => {
101-
return String::from("Invalid Base64 input.")
92+
return Err("Invalid padding position".to_string())
10293
}
10394
_ => (),
10495
}
@@ -117,12 +108,9 @@ pub fn base64_decode(input: &str) -> String {
117108
}
118109
}
119110

120-
String::from_utf8(result)
121-
.unwrap_or_else(|_| String::from("Invalid UTF-8 sequence in decoded data"))
111+
String::from_utf8(result).map_err(|_| "Invalid UTF-8 sequence in decoded data".to_string())
122112
}
123113

124-
pub fn text_decode(input: &str) -> [String; 2] {
125-
let base16 = base16_decode(input);
126-
let base64 = base64_decode(input);
127-
[base16, base64]
114+
pub fn text_decode(input: &str) -> [Result<String, String>; 2] {
115+
[base16_decode(input), base64_decode(input)]
128116
}

src/base/text/encode.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
pub fn base16_encode(input: &str) -> String {
1+
use std::string::FromUtf8Error;
2+
3+
pub fn base16_encode(input: &str) -> Result<String, FromUtf8Error> {
24
const BASE16_CHARS: &[u8] = b"0123456789abcdef";
35

46
let bytes = input.as_bytes();
@@ -9,10 +11,10 @@ pub fn base16_encode(input: &str) -> String {
911
result.push(BASE16_CHARS[(byte & 0x0F) as usize]);
1012
}
1113

12-
String::from_utf8(result).unwrap()
14+
String::from_utf8(result)
1315
}
1416

15-
pub fn base64_encode(input: &str) -> String {
17+
pub fn base64_encode(input: &str) -> Result<String, FromUtf8Error> {
1618
const BASE64_CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1719
let bytes = input.as_bytes();
1820
let mut result = Vec::with_capacity(((bytes.len() + 2) / 3) * 4);
@@ -52,11 +54,11 @@ pub fn base64_encode(input: &str) -> String {
5254
}
5355
}
5456

55-
String::from_utf8_lossy(&result).to_string()
57+
String::from_utf8(result)
5658
}
5759

58-
pub fn text_encode(input: &str) -> [String; 2] {
59-
let base16 = base16_encode(input);
60-
let base64 = base64_encode(input);
61-
[base16, base64]
60+
pub fn text_encode(input: &str) -> Result<[String; 2], FromUtf8Error> {
61+
let base16 = base16_encode(input)?;
62+
let base64 = base64_encode(input)?;
63+
Ok([base16, base64])
6264
}

src/base/text/test.rs

Lines changed: 77 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,94 @@
11
#[cfg(test)]
22
mod tests {
3-
use crate::base;
3+
use crate::base::text::decode::{base16_decode, base64_decode, text_decode};
4+
use crate::base::text::encode::{base16_encode, base64_encode, text_encode};
5+
6+
#[test]
7+
fn test_base16_encode() {
8+
assert_eq!(base16_encode("wutong").unwrap(), "7775746f6e67");
9+
assert_eq!(base16_encode("WUTONG").unwrap(), "5755544f4e47");
10+
assert_eq!(base16_encode("1234567890").unwrap(), "31323334353637383930");
11+
assert_eq!(base16_encode("").unwrap(), "");
12+
}
13+
14+
#[test]
15+
fn test_base64_encode() {
16+
assert_eq!(base64_encode("wutong").unwrap(), "d3V0b25n");
17+
assert_eq!(base64_encode("WUTONG").unwrap(), "V1VUT05H");
18+
assert_eq!(base64_encode("1234567890").unwrap(), "MTIzNDU2Nzg5MA==");
19+
assert_eq!(base64_encode("").unwrap(), "");
20+
}
421

522
#[test]
623
fn test_base16_decode() {
7-
assert_eq!(
8-
base::text::decode::base16_decode("7775746f6e67"),
9-
"wutong".to_string()
10-
);
11-
assert_eq!(
12-
base::text::decode::base16_decode("5755544f4e47"),
13-
"WUTONG".to_string()
14-
);
15-
assert_eq!(
16-
base::text::decode::base16_decode("31323334353637383930"),
17-
"1234567890".to_string()
18-
);
19-
assert_eq!(base::text::decode::base16_decode(""), "".to_string());
24+
assert_eq!(base16_decode("7775746f6e67").unwrap(), "wutong");
25+
assert_eq!(base16_decode("5755544f4e47").unwrap(), "WUTONG");
26+
assert_eq!(base16_decode("31323334353637383930").unwrap(), "1234567890");
27+
assert_eq!(base16_decode("").unwrap(), "");
28+
assert!(base16_decode("123").is_err());
29+
assert!(base16_decode("12345").is_err());
30+
assert!(base16_decode("123G").is_err());
2031
}
2132

2233
#[test]
2334
fn test_base64_decode() {
24-
assert_eq!(
25-
base::text::decode::base64_decode("d3V0b25n"),
26-
"wutong".to_string()
27-
);
28-
assert_eq!(
29-
base::text::decode::base64_decode("V1VUT05H"),
30-
"WUTONG".to_string()
31-
);
32-
assert_eq!(
33-
base::text::decode::base64_decode("MTIzNDU2Nzg5MA=="),
34-
"1234567890".to_string()
35-
);
36-
assert_eq!(base::text::decode::base64_decode(""), "".to_string());
35+
assert_eq!(base64_decode("d3V0b25n").unwrap(), "wutong");
36+
assert_eq!(base64_decode("V1VUT05H").unwrap(), "WUTONG");
37+
assert_eq!(base64_decode("MTIzNDU2Nzg5MA==").unwrap(), "1234567890");
38+
assert_eq!(base64_decode("").unwrap(), "");
39+
assert!(base64_decode("ABC").is_err());
40+
assert!(base64_decode("ABCD==").is_err());
41+
assert!(base64_decode("ABCD=").is_err());
42+
assert!(base64_decode("ABCG").is_err());
3743
}
3844

3945
#[test]
40-
fn test_base16_encode() {
41-
assert_eq!(
42-
base::text::encode::base16_encode("wutong"),
43-
"7775746f6e67".to_string()
44-
);
45-
assert_eq!(
46-
base::text::encode::base16_encode("WUTONG"),
47-
"5755544f4e47".to_string()
48-
);
49-
assert_eq!(
50-
base::text::encode::base16_encode("1234567890"),
51-
"31323334353637383930".to_string()
52-
);
53-
assert_eq!(base::text::encode::base16_encode(""), "".to_string());
46+
fn test_text_encode() {
47+
let [base16, base64] = text_encode("wutong").unwrap();
48+
assert_eq!(base16, "7775746f6e67");
49+
assert_eq!(base64, "d3V0b25n");
50+
51+
let [base16, base64] = text_encode("WUTONG").unwrap();
52+
assert_eq!(base16, "5755544f4e47");
53+
assert_eq!(base64, "V1VUT05H");
54+
55+
let [base16, base64] = text_encode("1234567890").unwrap();
56+
assert_eq!(base16, "31323334353637383930");
57+
assert_eq!(base64, "MTIzNDU2Nzg5MA==");
58+
59+
let [base16, base64] = text_encode("").unwrap();
60+
assert_eq!(base16, "");
61+
assert_eq!(base64, "");
5462
}
5563

5664
#[test]
57-
fn test_base64_encode() {
58-
assert_eq!(
59-
base::text::encode::base64_encode("wutong"),
60-
"d3V0b25n".to_string()
61-
);
62-
assert_eq!(
63-
base::text::encode::base64_encode("WUTONG"),
64-
"V1VUT05H".to_string()
65-
);
66-
assert_eq!(
67-
base::text::encode::base64_encode("1234567890"),
68-
"MTIzNDU2Nzg5MA==".to_string()
69-
);
70-
assert_eq!(base::text::encode::base64_encode(""), "".to_string());
65+
fn test_text_decode() {
66+
let [base16_res, base64_res] = text_decode("7775746f6e67");
67+
assert_eq!(base16_res.unwrap(), "wutong");
68+
assert!(base64_res.is_err());
69+
70+
let [base16_res, base64_res] = text_decode("d3V0b25n");
71+
assert!(base16_res.is_err());
72+
assert_eq!(base64_res.unwrap(), "wutong");
73+
74+
let [base16_res, base64_res] = text_decode("5755544f4e47");
75+
assert_eq!(base16_res.unwrap(), "WUTONG");
76+
assert!(base64_res.is_err());
77+
78+
let [base16_res, base64_res] = text_decode("V1VUT05H");
79+
assert!(base16_res.is_err());
80+
assert_eq!(base64_res.unwrap(), "WUTONG");
81+
82+
let [base16_res, base64_res] = text_decode("31323334353637383930");
83+
assert_eq!(base16_res.unwrap(), "1234567890");
84+
assert!(base64_res.is_err());
85+
86+
let [base16_res, base64_res] = text_decode("MTIzNDU2Nzg5MA==");
87+
assert!(base16_res.is_err());
88+
assert_eq!(base64_res.unwrap(), "1234567890");
89+
90+
let [base16_res, base64_res] = text_decode("");
91+
assert_eq!(base16_res.unwrap(), "");
92+
assert_eq!(base64_res.unwrap(), "");
7193
}
7294
}

0 commit comments

Comments
 (0)