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