1#![cfg_attr(test, feature(plugin))]
2#![cfg_attr(test, plugin(quickcheck_macros))]
3
4use std::io;
5
6pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, io::Error> {
8 let data = input.as_ref();
9 if data.is_empty() {
10 return Ok(vec![]);
11 }
12 strip_preamble(data)
13 .into_iter()
14 .map(|u| hex(*u))
15 .collect::<Result<Vec<_>, io::Error>>()
16 .map(|v| v.into_iter().skip_while(|u| *u == 0).collect::<Vec<_>>())
17 .map(|mut v| {
18 v.reverse(); v.chunks(2)
20 .map(|c| if c.len() == 1 { c[0] } else { c[1] * 16 + c[0] })
21 .rev() .collect::<Vec<_>>()
23 })
24}
25
26fn strip_preamble(data: &[u8]) -> &[u8] {
28 if data.len() >= 2 && data[0] == 0x30 && data[1] == 0x78 {
29 &data[2..]
30 } else {
31 data
32 }
33}
34
35fn hex(byte: u8) -> Result<u8, io::Error> {
37 if byte >= 0x30 && byte <= 0x39 {
38 return Ok(byte - 0x30);
39 }
40 if byte >= 0x41 && byte <= 0x46 {
41 return Ok(byte - 0x41 + 0xa);
42 }
43 if byte >= 0x61 && byte <= 0x66 {
44 return Ok(byte - 0x61 + 0xa);
45 }
46 Err(io::Error::new(
47 io::ErrorKind::InvalidInput,
48 "Did not supply a properly encoded hex value",
49 ))
50}
51
52#[cfg(test)]
53mod tests {
54 extern crate quickcheck;
55 use super::decode;
56 use quickcheck::TestResult;
57
58 #[test]
59 fn simple_case() {
60 let input = "0xc61bb3FA61A883Ed7723a2bF9D41D30B196fd999".to_lowercase();
61 let mut string = String::new();
62 string.push_str("0x");
63 for byte in decode(&input).unwrap() {
64 string.push_str(&format!("{:0>2x}", byte));
65 }
66 assert_eq!(input, string);
67 }
68
69 #[quickcheck]
70 fn decoding_is_identity(input: Vec<u8>) -> TestResult {
71 let mut encoded = String::with_capacity(input.len());
72 let mut zero_check = true;
73
74 for byte in &input {
75 encoded.push_str(&format!("{:0>2x}", byte));
76 if *byte != 0 {
77 zero_check = false;
78 }
79 }
80 if input.is_empty() {
81 let empty: Vec<u8> = vec![];
82 return TestResult::from_bool(empty == decode(encoded.as_bytes()).unwrap());
83 }
84 if zero_check {
85 return TestResult::from_bool(vec![0] == decode(encoded.as_bytes()).unwrap());
86 }
87 TestResult::from_bool(
88 input
89 .into_iter()
90 .skip_while(|u| *u == 0)
91 .collect::<Vec<_>>()
92 == decode(encoded.as_bytes()).unwrap(),
93 )
94 }
95
96 #[quickcheck]
97 fn decoding_is_identity_with_prefix(input: Vec<u8>) -> TestResult {
98 let mut encoded = String::with_capacity(input.len() + 2);
99 encoded.push_str("0x");
100 let mut zero_check = true;
101
102 for byte in &input {
103 encoded.push_str(&format!("{:0>2x}", byte));
104 if *byte != 0 {
105 zero_check = false;
106 }
107 }
108 if input.is_empty() {
109 let empty: Vec<u8> = vec![];
110 return TestResult::from_bool(empty == decode(encoded.as_bytes()).unwrap());
111 }
112 if zero_check {
113 return TestResult::from_bool(vec![0] == decode(encoded.as_bytes()).unwrap());
114 }
115 TestResult::from_bool(
116 input
117 .into_iter()
118 .skip_while(|u| *u == 0)
119 .collect::<Vec<_>>()
120 == decode(encoded.as_bytes()).unwrap(),
121 )
122 }
123}