(index<- ) ./libserialize/hex.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Fri May 9 13:02:28 2014
1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Hex binary-to-text encoding
12 use std::str;
13 use std::fmt;
14
15 /// A trait for converting a value to hexadecimal encoding
16 pub trait ToHex {
17 /// Converts the value of `self` to a hex value, returning the owned
18 /// string.
19 fn to_hex(&self) -> ~str;
20 }
21
22 static CHARS: &'static[u8] = bytes!("0123456789abcdef");
23
24 impl<'a> ToHex for &'a [u8] {
25 /**
26 * Turn a vector of `u8` bytes into a hexadecimal string.
27 *
28 * # Example
29 *
30 * ```rust
31 * extern crate serialize;
32 * use serialize::hex::ToHex;
33 *
34 * fn main () {
35 * let str = [52,32].to_hex();
36 * println!("{}", str);
37 * }
38 * ```
39 */
40 fn to_hex(&self) -> ~str {
41 let mut v = Vec::with_capacity(self.len() * 2);
42 for &byte in self.iter() {
43 v.push(CHARS[(byte >> 4) as uint]);
44 v.push(CHARS[(byte & 0xf) as uint]);
45 }
46
47 unsafe {
48 str::raw::from_utf8(v.as_slice()).to_owned()
49 }
50 }
51 }
52
53 /// A trait for converting hexadecimal encoded values
54 pub trait FromHex {
55 /// Converts the value of `self`, interpreted as hexadecimal encoded data,
56 /// into an owned vector of bytes, returning the vector.
57 fn from_hex(&self) -> Result<Vec<u8>, FromHexError>;
58 }
59
60 /// Errors that can occur when decoding a hex encoded string
61 pub enum FromHexError {
62 /// The input contained a character not part of the hex format
63 InvalidHexCharacter(char, uint),
64 /// The input had an invalid length
65 InvalidHexLength,
66 }
67
68 impl fmt::Show for FromHexError {
69 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70 match *self {
71 InvalidHexCharacter(ch, idx) =>
72 write!(f.buf, "Invalid character '{}' at position {}", ch, idx),
73 InvalidHexLength => write!(f.buf, "Invalid input length"),
74 }
75 }
76 }
77
78 impl<'a> FromHex for &'a str {
79 /**
80 * Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`)
81 * to the byte values it encodes.
82 *
83 * You can use the `from_utf8_owned` function in `std::str`
84 * to turn a `[u8]` into a string with characters corresponding to those
85 * values.
86 *
87 * # Example
88 *
89 * This converts a string literal to hexadecimal and back.
90 *
91 * ```rust
92 * extern crate serialize;
93 * use serialize::hex::{FromHex, ToHex};
94 *
95 * fn main () {
96 * let hello_str = "Hello, World".as_bytes().to_hex();
97 * println!("{}", hello_str);
98 * let bytes = hello_str.from_hex().unwrap();
99 * println!("{:?}", bytes);
100 * let result_str = StrBuf::from_utf8(bytes).unwrap();
101 * println!("{}", result_str);
102 * }
103 * ```
104 */
105 fn from_hex(&self) -> Result<Vec<u8>, FromHexError> {
106 // This may be an overestimate if there is any whitespace
107 let mut b = Vec::with_capacity(self.len() / 2);
108 let mut modulus = 0;
109 let mut buf = 0u8;
110
111 for (idx, byte) in self.bytes().enumerate() {
112 buf <<= 4;
113
114 match byte as char {
115 'A'..'F' => buf |= byte - ('A' as u8) + 10,
116 'a'..'f' => buf |= byte - ('a' as u8) + 10,
117 '0'..'9' => buf |= byte - ('0' as u8),
118 ' '|'\r'|'\n'|'\t' => {
119 buf >>= 4;
120 continue
121 }
122 _ => return Err(InvalidHexCharacter(self.char_at(idx), idx)),
123 }
124
125 modulus += 1;
126 if modulus == 2 {
127 modulus = 0;
128 b.push(buf);
129 }
130 }
131
132 match modulus {
133 0 => Ok(b.move_iter().collect()),
134 _ => Err(InvalidHexLength),
135 }
136 }
137 }
138
139 #[cfg(test)]
140 mod tests {
141 extern crate test;
142 use self::test::Bencher;
143 use hex::{FromHex, ToHex};
144
145 #[test]
146 pub fn test_to_hex() {
147 assert_eq!("foobar".as_bytes().to_hex(), "666f6f626172".to_owned());
148 }
149
150 #[test]
151 pub fn test_from_hex_okay() {
152 assert_eq!("666f6f626172".from_hex().unwrap().as_slice(),
153 "foobar".as_bytes());
154 assert_eq!("666F6F626172".from_hex().unwrap().as_slice(),
155 "foobar".as_bytes());
156 }
157
158 #[test]
159 pub fn test_from_hex_odd_len() {
160 assert!("666".from_hex().is_err());
161 assert!("66 6".from_hex().is_err());
162 }
163
164 #[test]
165 pub fn test_from_hex_invalid_char() {
166 assert!("66y6".from_hex().is_err());
167 }
168
169 #[test]
170 pub fn test_from_hex_ignores_whitespace() {
171 assert_eq!("666f 6f6\r\n26172 ".from_hex().unwrap().as_slice(),
172 "foobar".as_bytes());
173 }
174
175 #[test]
176 pub fn test_to_hex_all_bytes() {
177 for i in range(0, 256) {
178 assert_eq!([i as u8].to_hex(), format!("{:02x}", i as uint));
179 }
180 }
181
182 #[test]
183 pub fn test_from_hex_all_bytes() {
184 for i in range(0, 256) {
185 assert_eq!(format!("{:02x}", i as uint).from_hex().unwrap().as_slice(), &[i as u8]);
186 assert_eq!(format!("{:02X}", i as uint).from_hex().unwrap().as_slice(), &[i as u8]);
187 }
188 }
189
190 #[bench]
191 pub fn bench_to_hex(b: &mut Bencher) {
192 let s = "ã¤ãããããã ããªãã«ã² ã¯ã«ã¨ã¿ã¬ã½ ãããã©ã \
193 ã¦ã°ããªã¯ã¤ã ã±ãã³ã¨ã ã¢ãµãã¦ã¡ãã· ã±ãã¢ã»ã¹ã³";
194 b.iter(|| {
195 s.as_bytes().to_hex();
196 });
197 b.bytes = s.len() as u64;
198 }
199
200 #[bench]
201 pub fn bench_from_hex(b: &mut Bencher) {
202 let s = "ã¤ãããããã ããªãã«ã² ã¯ã«ã¨ã¿ã¬ã½ ãããã©ã \
203 ã¦ã°ããªã¯ã¤ã ã±ãã³ã¨ã ã¢ãµãã¦ã¡ãã· ã±ãã¢ã»ã¹ã³";
204 let sb = s.as_bytes().to_hex();
205 b.iter(|| {
206 sb.from_hex().unwrap();
207 });
208 b.bytes = sb.len() as u64;
209 }
210 }