(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  }