aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..c31c3a0
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,124 @@
1#[derive(Debug)]
2pub enum HexDecodeError {
3 InvalidByteCount,
4 InvalidHexCharacter,
5}
6
7fn hex_char_byte_to_value(c : u8) -> Result<u8, HexDecodeError> {
8 if !c.is_ascii_hexdigit() {
9 return Err(HexDecodeError::InvalidHexCharacter);
10 }
11 Ok( (c as char).to_digit(16).unwrap() as u8)
12}
13
14fn byte_to_hex_char(b : u8) -> char {
15 assert!(b <= 15);
16 match b {
17 digit if digit < 10 => ('0' as u8 + digit) as char,
18 letter => ('a' as u8 + letter - 10) as char
19 }
20}
21
22fn append_byte_hex_to_string(byte : u8, string : &mut String) {
23 let high = (byte & 0xF0) >> 4;
24 let low = byte & 0x0F;
25 string.push(byte_to_hex_char(high));
26 string.push(byte_to_hex_char(low));
27}
28
29pub fn decode_hex<T : AsRef<[u8]>>(string : T) -> Result<Vec<u8>, HexDecodeError> {
30 let chars = string.as_ref();
31 if chars.len() % 2 != 0 {
32 return Err(HexDecodeError::InvalidByteCount);
33 }
34 let mut data = Vec::new();
35 let mut index = 0;
36 let mut first_digit : u8 = 0;
37 for c in chars.iter() {
38 if index % 2 != 0 {
39 let second_digit = hex_char_byte_to_value(*c)?;
40 let value = first_digit * 16 + second_digit;
41 data.push(value);
42 }else {
43 first_digit = hex_char_byte_to_value(*c)?;
44 }
45 index += 1;
46 }
47 Ok(data)
48}
49
50pub fn encode_hex<T : AsRef<[u8]>>(data : T) -> String {
51 let mut string = String::new();
52 let data_ref = data.as_ref();
53 for b in data_ref.iter() {
54 append_byte_hex_to_string(*b, &mut string);
55 }
56 string
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn decode_zero_bytes_test() {
65 let string = "";
66 let data = decode_hex(string).unwrap();
67 assert_eq!(0, data.len());
68 }
69
70 #[test]
71 fn decode_one_byte_test() {
72 let string = "ff";
73 let data = decode_hex(string).unwrap();
74 assert_eq!(1, data.len());
75 assert_eq!(0xff, data[0]);
76 }
77
78 #[test]
79 fn decode_multiple_bytes_test() {
80 let string = "ffaabbccdd1122";
81 let data = decode_hex(string).unwrap();
82 assert_eq!(7, data.len());
83 assert_eq!(&[0xff, 0xaa, 0xbb, 0xcc, 0xdd, 0x11, 0x22], data.as_slice());
84 }
85
86 #[test]
87 fn decode_invalid_character_test() {
88 let string = "ffaabz";
89 match decode_hex(string) {
90 Err(HexDecodeError::InvalidHexCharacter) => {}
91 _ => panic!("Invalid result returned"),
92 }
93 }
94
95 #[test]
96 fn decode_invalid_character_length() {
97 let string = "ffaab";
98 match decode_hex(string) {
99 Err(HexDecodeError::InvalidByteCount) => {}
100 _ => panic!("Invalid result returned"),
101 }
102 }
103
104 #[test]
105 fn encode_zero_bytes() {
106 let data: &[u8; 0] = &[];
107 let string = encode_hex(&data);
108 assert_eq!(string, "");
109 }
110
111 #[test]
112 fn encode_one_byte() {
113 let data: &[u8; 1] = &[0xa1];
114 let string = encode_hex(&data);
115 assert_eq!(string, "a1");
116 }
117
118 #[test]
119 fn encode_multiple_bytes() {
120 let data: &[u8; 5] = &[0xaa, 0xbb, 0xcc, 0xdd, 0xee];
121 let string = encode_hex(&data);
122 assert_eq!(string, "aabbccddee");
123 }
124}