From 2266df51aa07eabd2f7745d410d3ddc4572ade21 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 4 Aug 2013 14:42:39 -0400 Subject: [PATCH 1/6] Added hexadecimal encoding module FromHex ignores whitespace and parses either upper or lower case hex digits. ToHex outputs lower case hex digits with no whitespace. Unlike ToBase64, ToHex doesn't allow you to configure the output format. I don't feel that it's super useful in this case. --- src/libextra/extra.rs | 1 + src/libextra/hex.rs | 238 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+) create mode 100644 src/libextra/hex.rs diff --git a/src/libextra/extra.rs b/src/libextra/extra.rs index 58929778a59e2..44781a1fd19b6 100644 --- a/src/libextra/extra.rs +++ b/src/libextra/extra.rs @@ -102,6 +102,7 @@ pub mod stats; pub mod semver; pub mod fileinput; pub mod flate; +pub mod hex; #[cfg(unicode)] mod unicode; diff --git a/src/libextra/hex.rs b/src/libextra/hex.rs new file mode 100644 index 0000000000000..7a1417e72d8cc --- /dev/null +++ b/src/libextra/hex.rs @@ -0,0 +1,238 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Hex binary-to-text encoding +use std::str; +use std::vec; + +/// A trait for converting a value to hexadecimal encoding +pub trait ToHex { + /// Converts the value of `self` to a hex value, returning the owned + /// string. + fn to_hex(&self) -> ~str; +} + +static CHARS: [char, ..16] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f']; + +impl<'self> ToHex for &'self [u8] { + /** + * Turn a vector of `u8` bytes into a hexadecimal string. + * + * # Example + * + * ~~~ {.rust} + * extern mod extra; + * use extra::hex::ToHex; + * + * fn main () { + * let str = [52,32].to_hex(); + * printfln!("%s", str); + * } + * ~~~ + */ + fn to_hex(&self) -> ~str { + let mut s = str::with_capacity(self.len() * 2); + for &byte in self.iter() { + s.push_char(CHARS[byte >> 4]); + s.push_char(CHARS[byte & 0xf]); + } + + s + } +} + +impl<'self> ToHex for &'self str { + /** + * Convert any string (literal, `@`, `&`, or `~`) to hexadecimal encoding. + * + * + * # Example + * + * ~~~ {.rust} + * extern mod extra; + * use extra::ToHex; + * + * fn main () { + * let str = "Hello, World".to_hex(); + * printfln!("%s", str); + * } + * ~~~ + * + */ + fn to_hex(&self) -> ~str { + self.as_bytes().to_hex() + } +} + +/// A trait for converting hexadecimal encoded values +pub trait FromHex { + /// Converts the value of `self`, interpreted as base64 encoded data, into + /// an owned vector of bytes, returning the vector. + fn from_hex(&self) -> Result<~[u8], ~str>; +} + +impl<'self> FromHex for &'self [u8] { + /** + * Convert hexadecimal `u8` vector into u8 byte values. + * Every 2 encoded characters is converted into 1 octet. + * + * # Example + * + * ~~~ {.rust} + * extern mod extra; + * use extra::hex::{ToHex, FromHex}; + * + * fn main () { + * let str = [52,32].to_hex(); + * printfln!("%s", str); + * let bytes = str.from_hex().get(); + * printfln!("%?", bytes); + * } + * ~~~ + */ + fn from_hex(&self) -> Result<~[u8], ~str> { + // This may be an overestimate if there is any whitespace + let mut b = vec::with_capacity(self.len() / 2); + let mut modulus = 0; + let mut buf = 0u8; + + for &byte in self.iter() { + buf <<= 4; + + match byte as char { + 'A'..'F' => buf |= byte - ('A' as u8) + 10, + 'a'..'f' => buf |= byte - ('a' as u8) + 10, + '0'..'9' => buf |= byte - ('0' as u8), + ' '|'\r'|'\n' => { + buf >>= 4; + loop + } + _ => return Err(~"Invalid hex char") + } + + modulus += 1; + if modulus == 2 { + modulus = 0; + b.push(buf); + } + } + + match modulus { + 0 => Ok(b), + _ => Err(~"Invalid input length") + } + } +} + +impl<'self> FromHex for &'self str { + /** + * Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`) + * to the byte values it encodes. + * + * You can use the `from_bytes` function in `std::str` + * to turn a `[u8]` into a string with characters corresponding to those + * values. + * + * # Example + * + * This converts a string literal to hexadecimal and back. + * + * ~~~ {.rust} + * extern mod extra; + * use extra::hex::{FromHex, ToHex}; + * use std::str; + * + * fn main () { + * let hello_str = "Hello, World".to_hex(); + * printfln!("%s", hello_str); + * let bytes = hello_str.from_hex().get(); + * printfln!("%?", bytes); + * let result_str = str::from_bytes(bytes); + * printfln!("%s", result_str); + * } + * ~~~ + */ + fn from_hex(&self) -> Result<~[u8], ~str> { + self.as_bytes().from_hex() + } +} + +#[cfg(test)] +mod tests { + use test::BenchHarness; + use hex::*; + + #[test] + pub fn test_to_hex() { + assert_eq!("foobar".to_hex(), ~"666f6f626172"); + } + + #[test] + pub fn test_from_hex_okay() { + assert_eq!("666f6f626172".from_hex().get(), + "foobar".as_bytes().to_owned()); + assert_eq!("666F6F626172".from_hex().get(), + "foobar".as_bytes().to_owned()); + } + + #[test] + pub fn test_from_hex_odd_len() { + assert!("666".from_hex().is_err()); + assert!("66 6".from_hex().is_err()); + } + + #[test] + pub fn test_from_hex_invalid_char() { + assert!("66y6".from_hex().is_err()); + } + + #[test] + pub fn test_from_hex_ignores_whitespace() { + assert_eq!("666f 6f6\r\n26172 ".from_hex().get(), + "foobar".as_bytes().to_owned()); + } + + #[test] + pub fn test_to_hex_all_bytes() { + for i in range(0, 256) { + assert_eq!([i as u8].to_hex(), fmt!("%02x", i as uint)); + } + } + + #[test] + pub fn test_from_hex_all_bytes() { + for i in range(0, 256) { + assert_eq!(fmt!("%02x", i as uint).from_hex().get(), ~[i as u8]); + assert_eq!(fmt!("%02X", i as uint).from_hex().get(), ~[i as u8]); + } + } + + #[bench] + pub fn bench_to_hex(bh: & mut BenchHarness) { + let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ + ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; + do bh.iter { + s.to_hex(); + } + bh.bytes = s.len() as u64; + } + + #[bench] + pub fn bench_from_hex(bh: & mut BenchHarness) { + let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ + ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; + let b = s.to_hex(); + do bh.iter { + b.from_hex(); + } + bh.bytes = b.len() as u64; + } +} From 463e2416e98238e294d332397048b106d85fd474 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 4 Aug 2013 16:09:04 -0400 Subject: [PATCH 2/6] Some minor hex changes --- src/libextra/hex.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libextra/hex.rs b/src/libextra/hex.rs index 7a1417e72d8cc..5609c566d9273 100644 --- a/src/libextra/hex.rs +++ b/src/libextra/hex.rs @@ -57,7 +57,7 @@ impl<'self> ToHex for &'self str { * # Example * * ~~~ {.rust} - * extern mod extra; + * extern mod extra; * use extra::ToHex; * * fn main () { @@ -74,8 +74,8 @@ impl<'self> ToHex for &'self str { /// A trait for converting hexadecimal encoded values pub trait FromHex { - /// Converts the value of `self`, interpreted as base64 encoded data, into - /// an owned vector of bytes, returning the vector. + /// Converts the value of `self`, interpreted as hexadecimal encoded data, + /// into an owned vector of bytes, returning the vector. fn from_hex(&self) -> Result<~[u8], ~str>; } @@ -83,6 +83,7 @@ impl<'self> FromHex for &'self [u8] { /** * Convert hexadecimal `u8` vector into u8 byte values. * Every 2 encoded characters is converted into 1 octet. + * Whitespace is ignored. * * # Example * @@ -104,18 +105,19 @@ impl<'self> FromHex for &'self [u8] { let mut modulus = 0; let mut buf = 0u8; - for &byte in self.iter() { + for (idx, &byte) in self.iter().enumerate() { buf <<= 4; match byte as char { 'A'..'F' => buf |= byte - ('A' as u8) + 10, 'a'..'f' => buf |= byte - ('a' as u8) + 10, '0'..'9' => buf |= byte - ('0' as u8), - ' '|'\r'|'\n' => { + ' '|'\r'|'\n'|'\t' => { buf >>= 4; loop } - _ => return Err(~"Invalid hex char") + _ => return Err(fmt!("Invalid byte '%c' found at position %u", + byte as char, idx)) } modulus += 1; From ff5fdffc135f55e751dfcff0df1f52b9f4faad17 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 4 Aug 2013 23:51:26 -0400 Subject: [PATCH 3/6] ToBase64 and ToHex perf improvements The overhead of str::push_char is high enough to cripple the performance of these two functions. I've switched them to build the output in a ~[u8] and then convert to a string later. Since we know exactly the bytes going into the vector, we can use the unsafe version to avoid the is_utf8 check. I could have riced it further with vec::raw::get, but it only added ~10MB/s so I didn't think it was worth it. ToHex is still ~30% slower than FromHex, which is puzzling. Before: ``` test base64::test::from_base64 ... bench: 1000 ns/iter (+/- 349) = 204 MB/s test base64::test::to_base64 ... bench: 2390 ns/iter (+/- 1130) = 63 MB/s ... test hex::tests::bench_from_hex ... bench: 884 ns/iter (+/- 220) = 341 MB/s test hex::tests::bench_to_hex ... bench: 2453 ns/iter (+/- 919) = 61 MB/s ``` After: ``` test base64::test::from_base64 ... bench: 1271 ns/iter (+/- 600) = 160 MB/s test base64::test::to_base64 ... bench: 759 ns/iter (+/- 286) = 198 MB/s ... test hex::tests::bench_from_hex ... bench: 875 ns/iter (+/- 377) = 345 MB/s test hex::tests::bench_to_hex ... bench: 593 ns/iter (+/- 240) = 254 MB/s ``` --- src/libextra/base64.rs | 61 +++++++++++++++++++++--------------------- src/libextra/hex.rs | 14 +++++----- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/libextra/base64.rs b/src/libextra/base64.rs index 550b891a4db16..d6ab36ca7215e 100644 --- a/src/libextra/base64.rs +++ b/src/libextra/base64.rs @@ -9,6 +9,7 @@ // except according to those terms. //! Base64 binary-to-text encoding +use std::str; /// Available encoding character sets pub enum CharacterSet { @@ -40,21 +41,13 @@ pub static URL_SAFE: Config = pub static MIME: Config = Config {char_set: Standard, pad: true, line_length: Some(76)}; -static STANDARD_CHARS: [char, ..64] = [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' -]; - -static URLSAFE_CHARS: [char, ..64] = [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' -]; +static STANDARD_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyz", + "0123456789+/"); + +static URLSAFE_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyz", + "0123456789-_"); /// A trait for converting a value to base64 encoding. pub trait ToBase64 { @@ -80,12 +73,12 @@ impl<'self> ToBase64 for &'self [u8] { * ~~~ */ fn to_base64(&self, config: Config) -> ~str { - let chars = match config.char_set { + let bytes = match config.char_set { Standard => STANDARD_CHARS, UrlSafe => URLSAFE_CHARS }; - let mut s = ~""; + let mut v: ~[u8] = ~[]; let mut i = 0; let mut cur_length = 0; let len = self.len(); @@ -93,7 +86,8 @@ impl<'self> ToBase64 for &'self [u8] { match config.line_length { Some(line_length) => if cur_length >= line_length { - s.push_str("\r\n"); + v.push('\r' as u8); + v.push('\n' as u8); cur_length = 0; }, None => () @@ -104,10 +98,10 @@ impl<'self> ToBase64 for &'self [u8] { (self[i + 2] as u32); // This 24-bit number gets separated into four 6-bit numbers. - s.push_char(chars[(n >> 18) & 63]); - s.push_char(chars[(n >> 12) & 63]); - s.push_char(chars[(n >> 6 ) & 63]); - s.push_char(chars[n & 63]); + v.push(bytes[(n >> 18) & 63]); + v.push(bytes[(n >> 12) & 63]); + v.push(bytes[(n >> 6 ) & 63]); + v.push(bytes[n & 63]); cur_length += 4; i += 3; @@ -117,7 +111,8 @@ impl<'self> ToBase64 for &'self [u8] { match config.line_length { Some(line_length) => if cur_length >= line_length { - s.push_str("\r\n"); + v.push('\r' as u8); + v.push('\n' as u8); }, None => () } @@ -129,25 +124,29 @@ impl<'self> ToBase64 for &'self [u8] { 0 => (), 1 => { let n = (self[i] as u32) << 16; - s.push_char(chars[(n >> 18) & 63]); - s.push_char(chars[(n >> 12) & 63]); + v.push(bytes[(n >> 18) & 63]); + v.push(bytes[(n >> 12) & 63]); if config.pad { - s.push_str("=="); + v.push('=' as u8); + v.push('=' as u8); } } 2 => { let n = (self[i] as u32) << 16 | (self[i + 1u] as u32) << 8; - s.push_char(chars[(n >> 18) & 63]); - s.push_char(chars[(n >> 12) & 63]); - s.push_char(chars[(n >> 6 ) & 63]); + v.push(bytes[(n >> 18) & 63]); + v.push(bytes[(n >> 12) & 63]); + v.push(bytes[(n >> 6 ) & 63]); if config.pad { - s.push_char('='); + v.push('=' as u8); } } _ => fail!("Algebra is broken, please alert the math police") } - s + + unsafe { + str::raw::from_bytes_owned(v) + } } } diff --git a/src/libextra/hex.rs b/src/libextra/hex.rs index 5609c566d9273..748d039158807 100644 --- a/src/libextra/hex.rs +++ b/src/libextra/hex.rs @@ -19,8 +19,7 @@ pub trait ToHex { fn to_hex(&self) -> ~str; } -static CHARS: [char, ..16] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'a', 'b', 'c', 'd', 'e', 'f']; +static CHARS: &'static[u8] = bytes!("0123456789abcdef"); impl<'self> ToHex for &'self [u8] { /** @@ -39,13 +38,16 @@ impl<'self> ToHex for &'self [u8] { * ~~~ */ fn to_hex(&self) -> ~str { - let mut s = str::with_capacity(self.len() * 2); + // +1 for NULL terminator + let mut v = vec::with_capacity(self.len() * 2 + 1); for &byte in self.iter() { - s.push_char(CHARS[byte >> 4]); - s.push_char(CHARS[byte & 0xf]); + v.push(CHARS[byte >> 4]); + v.push(CHARS[byte & 0xf]); } - s + unsafe { + str::raw::from_bytes_owned(v) + } } } From 858e166119d81e76b8909da880b3b3d0e25718c3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 5 Aug 2013 00:08:13 -0400 Subject: [PATCH 4/6] Removing space for NULL terminator String NULL terminators are going away soon, so we may as well get rid of this now so it doesn't rot. --- src/libextra/hex.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libextra/hex.rs b/src/libextra/hex.rs index 748d039158807..ddd1276a98798 100644 --- a/src/libextra/hex.rs +++ b/src/libextra/hex.rs @@ -38,8 +38,7 @@ impl<'self> ToHex for &'self [u8] { * ~~~ */ fn to_hex(&self) -> ~str { - // +1 for NULL terminator - let mut v = vec::with_capacity(self.len() * 2 + 1); + let mut v = vec::with_capacity(self.len() * 2); for &byte in self.iter() { v.push(CHARS[byte >> 4]); v.push(CHARS[byte & 0xf]); From e6176513842da1dd9e17d8536e7d76125a1bc610 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 5 Aug 2013 01:25:15 -0400 Subject: [PATCH 5/6] Removed convenience encoding trait impls Encoding should really only be done from [u8]<->str. The extra convenience implementations don't really have a place, especially since they're so trivial. Also improved error messages in FromBase64. --- src/libextra/base64.rs | 125 ++++++++++++++--------------------------- src/libextra/hex.rs | 92 ++++++++---------------------- 2 files changed, 63 insertions(+), 154 deletions(-) diff --git a/src/libextra/base64.rs b/src/libextra/base64.rs index d6ab36ca7215e..b4431004bd74c 100644 --- a/src/libextra/base64.rs +++ b/src/libextra/base64.rs @@ -150,29 +150,6 @@ impl<'self> ToBase64 for &'self [u8] { } } -impl<'self> ToBase64 for &'self str { - /** - * Convert any string (literal, `@`, `&`, or `~`) to base64 encoding. - * - * - * # Example - * - * ~~~ {.rust} - * extern mod extra; - * use extra::base64::{ToBase64, standard}; - * - * fn main () { - * let str = "Hello, World".to_base64(standard); - * printfln!("%s", str); - * } - * ~~~ - * - */ - fn to_base64(&self, config: Config) -> ~str { - self.as_bytes().to_base64(config) - } -} - /// A trait for converting from base64 encoded values. pub trait FromBase64 { /// Converts the value of `self`, interpreted as base64 encoded data, into @@ -180,22 +157,31 @@ pub trait FromBase64 { fn from_base64(&self) -> Result<~[u8], ~str>; } -impl<'self> FromBase64 for &'self [u8] { +impl<'self> FromBase64 for &'self str { /** - * Convert base64 `u8` vector into u8 byte values. - * Every 4 encoded characters is converted into 3 octets, modulo padding. + * Convert any base64 encoded string (literal, `@`, `&`, or `~`) + * to the byte values it encodes. + * + * You can use the `from_bytes` function in `std::str` + * to turn a `[u8]` into a string with characters corresponding to those + * values. * * # Example * + * This converts a string literal to base64 and back. + * * ~~~ {.rust} * extern mod extra; * use extra::base64::{ToBase64, FromBase64, standard}; + * use std::str; * * fn main () { - * let str = [52,32].to_base64(standard); - * printfln!("%s", str); - * let bytes = str.from_base64(); + * let hello_str = "Hello, World".to_base64(standard); + * printfln!("%s", hello_str); + * let bytes = hello_str.from_base64(); * printfln!("%?", bytes); + * let result_str = str::from_bytes(bytes); + * printfln!("%s", result_str); * } * ~~~ */ @@ -204,12 +190,11 @@ impl<'self> FromBase64 for &'self [u8] { let mut buf: u32 = 0; let mut modulus = 0; - let mut it = self.iter(); - for &byte in it { - let ch = byte as char; + let mut it = self.byte_iter().enumerate(); + for (idx, byte) in it { let val = byte as u32; - match ch { + match byte as char { 'A'..'Z' => buf |= val - 0x41, 'a'..'z' => buf |= val - 0x47, '0'..'9' => buf |= val + 0x04, @@ -217,7 +202,8 @@ impl<'self> FromBase64 for &'self [u8] { '/'|'_' => buf |= 0x3F, '\r'|'\n' => loop, '=' => break, - _ => return Err(~"Invalid Base64 character") + _ => return Err(fmt!("Invalid character '%c' at position %u", + self.char_at(idx), idx)) } buf <<= 6; @@ -230,8 +216,11 @@ impl<'self> FromBase64 for &'self [u8] { } } - if !it.all(|&byte| {byte as char == '='}) { - return Err(~"Invalid Base64 character"); + for (idx, byte) in it { + if (byte as char) != '=' { + return Err(fmt!("Invalid character '%c' at position %u", + self.char_at(idx), idx)); + } } match modulus { @@ -250,39 +239,6 @@ impl<'self> FromBase64 for &'self [u8] { } } -impl<'self> FromBase64 for &'self str { - /** - * Convert any base64 encoded string (literal, `@`, `&`, or `~`) - * to the byte values it encodes. - * - * You can use the `from_bytes` function in `std::str` - * to turn a `[u8]` into a string with characters corresponding to those - * values. - * - * # Example - * - * This converts a string literal to base64 and back. - * - * ~~~ {.rust} - * extern mod extra; - * use extra::base64::{ToBase64, FromBase64, standard}; - * use std::str; - * - * fn main () { - * let hello_str = "Hello, World".to_base64(standard); - * printfln!("%s", hello_str); - * let bytes = hello_str.from_base64(); - * printfln!("%?", bytes); - * let result_str = str::from_bytes(bytes); - * printfln!("%s", result_str); - * } - * ~~~ - */ - fn from_base64(&self) -> Result<~[u8], ~str> { - self.as_bytes().from_base64() - } -} - #[cfg(test)] mod test { use test::BenchHarness; @@ -290,27 +246,28 @@ mod test { #[test] fn test_to_base64_basic() { - assert_eq!("".to_base64(STANDARD), ~""); - assert_eq!("f".to_base64(STANDARD), ~"Zg=="); - assert_eq!("fo".to_base64(STANDARD), ~"Zm8="); - assert_eq!("foo".to_base64(STANDARD), ~"Zm9v"); - assert_eq!("foob".to_base64(STANDARD), ~"Zm9vYg=="); - assert_eq!("fooba".to_base64(STANDARD), ~"Zm9vYmE="); - assert_eq!("foobar".to_base64(STANDARD), ~"Zm9vYmFy"); + assert_eq!("".as_bytes().to_base64(STANDARD), ~""); + assert_eq!("f".as_bytes().to_base64(STANDARD), ~"Zg=="); + assert_eq!("fo".as_bytes().to_base64(STANDARD), ~"Zm8="); + assert_eq!("foo".as_bytes().to_base64(STANDARD), ~"Zm9v"); + assert_eq!("foob".as_bytes().to_base64(STANDARD), ~"Zm9vYg=="); + assert_eq!("fooba".as_bytes().to_base64(STANDARD), ~"Zm9vYmE="); + assert_eq!("foobar".as_bytes().to_base64(STANDARD), ~"Zm9vYmFy"); } #[test] fn test_to_base64_line_break() { assert!(![0u8, 1000].to_base64(Config {line_length: None, ..STANDARD}) .contains("\r\n")); - assert_eq!("foobar".to_base64(Config {line_length: Some(4), ..STANDARD}), + assert_eq!("foobar".as_bytes().to_base64(Config {line_length: Some(4), + ..STANDARD}), ~"Zm9v\r\nYmFy"); } #[test] fn test_to_base64_padding() { - assert_eq!("f".to_base64(Config {pad: false, ..STANDARD}), ~"Zg"); - assert_eq!("fo".to_base64(Config {pad: false, ..STANDARD}), ~"Zm8"); + assert_eq!("f".as_bytes().to_base64(Config {pad: false, ..STANDARD}), ~"Zg"); + assert_eq!("fo".as_bytes().to_base64(Config {pad: false, ..STANDARD}), ~"Zm8"); } #[test] @@ -344,7 +301,7 @@ mod test { #[test] fn test_from_base64_invalid_char() { assert!("Zm$=".from_base64().is_err()) - assert!("Zg==$".from_base64().is_err()); + assert!("Zg==$".from_base64().is_err()); } #[test] @@ -368,20 +325,20 @@ mod test { } #[bench] - pub fn to_base64(bh: & mut BenchHarness) { + pub fn bench_to_base64(bh: & mut BenchHarness) { let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; do bh.iter { - s.to_base64(STANDARD); + s.as_bytes().to_base64(STANDARD); } bh.bytes = s.len() as u64; } #[bench] - pub fn from_base64(bh: & mut BenchHarness) { + pub fn bench_from_base64(bh: & mut BenchHarness) { let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; - let b = s.to_base64(STANDARD); + let b = s.as_bytes().to_base64(STANDARD); do bh.iter { b.from_base64(); } diff --git a/src/libextra/hex.rs b/src/libextra/hex.rs index ddd1276a98798..2a6a8a5205564 100644 --- a/src/libextra/hex.rs +++ b/src/libextra/hex.rs @@ -50,29 +50,6 @@ impl<'self> ToHex for &'self [u8] { } } -impl<'self> ToHex for &'self str { - /** - * Convert any string (literal, `@`, `&`, or `~`) to hexadecimal encoding. - * - * - * # Example - * - * ~~~ {.rust} - * extern mod extra; - * use extra::ToHex; - * - * fn main () { - * let str = "Hello, World".to_hex(); - * printfln!("%s", str); - * } - * ~~~ - * - */ - fn to_hex(&self) -> ~str { - self.as_bytes().to_hex() - } -} - /// A trait for converting hexadecimal encoded values pub trait FromHex { /// Converts the value of `self`, interpreted as hexadecimal encoded data, @@ -80,23 +57,31 @@ pub trait FromHex { fn from_hex(&self) -> Result<~[u8], ~str>; } -impl<'self> FromHex for &'self [u8] { +impl<'self> FromHex for &'self str { /** - * Convert hexadecimal `u8` vector into u8 byte values. - * Every 2 encoded characters is converted into 1 octet. - * Whitespace is ignored. + * Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`) + * to the byte values it encodes. + * + * You can use the `from_bytes` function in `std::str` + * to turn a `[u8]` into a string with characters corresponding to those + * values. * * # Example * + * This converts a string literal to hexadecimal and back. + * * ~~~ {.rust} * extern mod extra; - * use extra::hex::{ToHex, FromHex}; + * use extra::hex::{FromHex, ToHex}; + * use std::str; * * fn main () { - * let str = [52,32].to_hex(); - * printfln!("%s", str); - * let bytes = str.from_hex().get(); + * let hello_str = "Hello, World".to_hex(); + * printfln!("%s", hello_str); + * let bytes = hello_str.from_hex().get(); * printfln!("%?", bytes); + * let result_str = str::from_bytes(bytes); + * printfln!("%s", result_str); * } * ~~~ */ @@ -106,7 +91,7 @@ impl<'self> FromHex for &'self [u8] { let mut modulus = 0; let mut buf = 0u8; - for (idx, &byte) in self.iter().enumerate() { + for (idx, byte) in self.byte_iter().enumerate() { buf <<= 4; match byte as char { @@ -117,8 +102,8 @@ impl<'self> FromHex for &'self [u8] { buf >>= 4; loop } - _ => return Err(fmt!("Invalid byte '%c' found at position %u", - byte as char, idx)) + _ => return Err(fmt!("Invalid character '%c' at position %u", + self.char_at(idx), idx)) } modulus += 1; @@ -135,39 +120,6 @@ impl<'self> FromHex for &'self [u8] { } } -impl<'self> FromHex for &'self str { - /** - * Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`) - * to the byte values it encodes. - * - * You can use the `from_bytes` function in `std::str` - * to turn a `[u8]` into a string with characters corresponding to those - * values. - * - * # Example - * - * This converts a string literal to hexadecimal and back. - * - * ~~~ {.rust} - * extern mod extra; - * use extra::hex::{FromHex, ToHex}; - * use std::str; - * - * fn main () { - * let hello_str = "Hello, World".to_hex(); - * printfln!("%s", hello_str); - * let bytes = hello_str.from_hex().get(); - * printfln!("%?", bytes); - * let result_str = str::from_bytes(bytes); - * printfln!("%s", result_str); - * } - * ~~~ - */ - fn from_hex(&self) -> Result<~[u8], ~str> { - self.as_bytes().from_hex() - } -} - #[cfg(test)] mod tests { use test::BenchHarness; @@ -175,7 +127,7 @@ mod tests { #[test] pub fn test_to_hex() { - assert_eq!("foobar".to_hex(), ~"666f6f626172"); + assert_eq!("foobar".as_bytes().to_hex(), ~"666f6f626172"); } #[test] @@ -223,7 +175,7 @@ mod tests { let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; do bh.iter { - s.to_hex(); + s.as_bytes().to_hex(); } bh.bytes = s.len() as u64; } @@ -232,7 +184,7 @@ mod tests { pub fn bench_from_hex(bh: & mut BenchHarness) { let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; - let b = s.to_hex(); + let b = s.as_bytes().to_hex(); do bh.iter { b.from_hex(); } From 3b441c485f10722e58f71957b78e5950c53757d4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 6 Aug 2013 10:42:06 -0700 Subject: [PATCH 6/6] Result::get -> Result::unwrap --- src/libextra/hex.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libextra/hex.rs b/src/libextra/hex.rs index 2a6a8a5205564..d5345cb956b8f 100644 --- a/src/libextra/hex.rs +++ b/src/libextra/hex.rs @@ -78,7 +78,7 @@ impl<'self> FromHex for &'self str { * fn main () { * let hello_str = "Hello, World".to_hex(); * printfln!("%s", hello_str); - * let bytes = hello_str.from_hex().get(); + * let bytes = hello_str.from_hex().unwrap(); * printfln!("%?", bytes); * let result_str = str::from_bytes(bytes); * printfln!("%s", result_str); @@ -132,9 +132,9 @@ mod tests { #[test] pub fn test_from_hex_okay() { - assert_eq!("666f6f626172".from_hex().get(), + assert_eq!("666f6f626172".from_hex().unwrap(), "foobar".as_bytes().to_owned()); - assert_eq!("666F6F626172".from_hex().get(), + assert_eq!("666F6F626172".from_hex().unwrap(), "foobar".as_bytes().to_owned()); } @@ -151,7 +151,7 @@ mod tests { #[test] pub fn test_from_hex_ignores_whitespace() { - assert_eq!("666f 6f6\r\n26172 ".from_hex().get(), + assert_eq!("666f 6f6\r\n26172 ".from_hex().unwrap(), "foobar".as_bytes().to_owned()); } @@ -165,8 +165,8 @@ mod tests { #[test] pub fn test_from_hex_all_bytes() { for i in range(0, 256) { - assert_eq!(fmt!("%02x", i as uint).from_hex().get(), ~[i as u8]); - assert_eq!(fmt!("%02X", i as uint).from_hex().get(), ~[i as u8]); + assert_eq!(fmt!("%02x", i as uint).from_hex().unwrap(), ~[i as u8]); + assert_eq!(fmt!("%02X", i as uint).from_hex().unwrap(), ~[i as u8]); } }