Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions cmp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ publish = false
[dependencies]
base64 = { git = "https://github.com/alicemaz/rust-base64" }
data-encoding = { path = "../lib" }
libc = "0.2.21"
rustc-serialize = "0.3.23"
lazy_static = "0.2.8"
libc = "0.2"
rustc-serialize = "0.3"
lazy_static = "1"

[build-dependencies]
cc = "1.0"
cc = "1"
4 changes: 2 additions & 2 deletions cmp/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ fn difference() {
let x = b"AAB=";
assert_eq!(BASE64.decode(x).err().unwrap(), DecodeError { position: 2, kind: Trailing });
assert_eq!(x.from_base64().unwrap(), vec![0, 0]);
assert_eq!(base64::decode(x).unwrap(), vec![0, 0]);
assert!(base64::decode(x).is_err());
let x = b"AA\nB=";
assert_eq!(BASE64.decode(x).err().unwrap(), DecodeError { position: 4, kind: Length });
assert_eq!(x.from_base64().unwrap(), vec![0, 0]);
assert_eq!(base64::decode(x).err().unwrap(), base64::DecodeError::InvalidLength);
let x = b"AAB";
assert_eq!(BASE64.decode(x).err().unwrap(), DecodeError { position: 0, kind: Length });
assert_eq!(x.from_base64().unwrap(), vec![0, 0]);
assert_eq!(base64::decode(x).unwrap(), vec![0, 0]);
assert!(base64::decode(x).is_err());
let x = b"AAA";
assert_eq!(BASE64.decode(x).err().unwrap(), DecodeError { position: 0, kind: Length });
assert_eq!(x.from_base64().unwrap(), vec![0, 0]);
Expand Down
2 changes: 1 addition & 1 deletion lib/macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ stable = ["data-encoding-macro-internal/stable", "proc-macro-hack"]
[dependencies]
data-encoding = { version = "2.1", path = ".." }
data-encoding-macro-internal = { version = "0.1.6", path = "internal" }
proc-macro-hack = { version = "0.4", optional = true }
proc-macro-hack = { version = "0.5", optional = true }
4 changes: 2 additions & 2 deletions lib/macro/internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ stable = ["proc-macro-hack"]

[dependencies]
data-encoding = { version = "2.1", path = "../.." }
proc-macro-hack = { version = "0.4.0", optional = true }
syn = "0.11.11"
proc-macro-hack = { version = "0.5", optional = true }
syn = "0.15"
167 changes: 18 additions & 149 deletions lib/macro/internal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,26 @@

extern crate proc_macro;
#[cfg(feature = "stable")]
#[macro_use]
extern crate proc_macro_hack;
extern crate syn;

extern crate data_encoding;

#[cfg(not(feature = "stable"))]
use proc_macro::token_stream::IntoIter;
#[cfg(not(feature = "stable"))]
use proc_macro::{TokenStream, TokenTree};
use std::collections::HashMap;
#[cfg(feature = "stable")]
use syn::parse::IResult;
#[cfg(feature = "stable")]
use syn::{Lit, Token, TokenTree};
use proc_macro_hack::proc_macro_hack;
use std::collections::HashMap;

use data_encoding::{BitOrder, Encoding, Specification, Translate, Wrap};

#[cfg(not(feature = "stable"))]
fn parse_op(tokens: &mut IntoIter, op: char, key: &str) {
match tokens.next() {
Some(TokenTree::Punct(ref x)) if x.as_char() == op => (),
_ => panic!("expected {:?} after {}", op, key),
}
}
#[cfg(feature = "stable")]
fn parse_op<'a>(input: &'a str, op: Token, key: &str) -> &'a str {
match syn::parse::tt(input) {
IResult::Done(rest, TokenTree::Token(ref x)) if x == &op => rest,
_ => panic!("expected {:?} after {}", op, key),
}
}

#[cfg(not(feature = "stable"))]
fn parse_map(mut tokens: IntoIter) -> HashMap<String, TokenTree> {
let mut map = HashMap::new();
while let Some(key) = tokens.next() {
Expand All @@ -62,54 +48,18 @@ fn parse_map(mut tokens: IntoIter) -> HashMap<String, TokenTree> {
}
map
}
#[cfg(feature = "stable")]
fn parse_map(mut input: &str) -> HashMap<String, Token> {
let mut map = HashMap::new();
while let IResult::Done(rest, key) = syn::parse::tt(input) {
input = rest;
let key = match key {
TokenTree::Token(Token::Ident(key)) => key,
_ => panic!("expected key got {:?}", key),
};
input = parse_op(input, Token::Colon, key.as_ref());
let value = match syn::parse::tt(input) {
IResult::Done(rest, TokenTree::Token(value)) => {
input = rest;
value
}
_ => panic!("expected value for {}", key),
};
input = parse_op(input, Token::Comma, key.as_ref());
let _ = map.insert(key.as_ref().to_string(), value);
}
map
}

#[cfg(not(feature = "stable"))]
fn get_string(map: &mut HashMap<String, TokenTree>, key: &str) -> String {
let node = match map.remove(key) {
None => return String::new(),
Some(node) => node,
};
let literal = match node {
TokenTree::Literal(literal) => literal,
_ => panic!("expected literal for {}", key),
};
match syn::parse::string(&literal.to_string()) {
syn::parse::IResult::Done(_, result) => result.value,
match syn::parse::<syn::LitStr>(node.into()) {
Ok(result) => result.value(),
_ => panic!("expected string for {}", key),
}
}
#[cfg(feature = "stable")]
fn get_string(map: &mut HashMap<String, Token>, key: &str) -> String {
match map.remove(key) {
None => String::new(),
Some(Token::Literal(Lit::Str(value, _))) => value,
Some(_) => panic!("expected string literal for {}", key),
}
}

#[cfg(not(feature = "stable"))]
fn get_usize(map: &mut HashMap<String, TokenTree>, key: &str) -> usize {
let node = match map.remove(key) {
None => return 0,
Expand All @@ -124,60 +74,32 @@ fn get_usize(map: &mut HashMap<String, TokenTree>, key: &str) -> usize {
Err(error) => panic!("expected usize for {}: {}", key, error),
}
}
#[cfg(feature = "stable")]
fn get_usize(map: &mut HashMap<String, Token>, key: &str) -> usize {
match map.remove(key) {
None => 0,
Some(Token::Literal(Lit::Int(value, _))) => value as usize,
Some(_) => panic!("expected usize for {}", key),
}
}

#[cfg(not(feature = "stable"))]
fn get_padding(map: &mut HashMap<String, TokenTree>) -> Option<char> {
let node = match map.remove("padding") {
None => return None,
Some(node) => node,
};
let literal = match node {
TokenTree::Ident(ref ident) if format!("{}", ident) == "None" => return None,
TokenTree::Literal(literal) => literal,
_ => panic!("expected literal for padding"),
};
Some(syn::parse::character(&literal.to_string()).expect("expected char for padding"))
}
#[cfg(feature = "stable")]
fn get_padding(map: &mut HashMap<String, Token>) -> Option<char> {
match map.remove("padding") {
None => None,
Some(Token::Ident(ref ident)) if ident.as_ref() == "None" => None,
Some(Token::Literal(Lit::Char(value))) => Some(value),
Some(_) => panic!("expected char for padding"),
if let Ok(result) = syn::parse::<syn::LitChar>(node.clone().into()) {
return Some(result.value());
}
match syn::parse::<syn::Ident>(node.into()) {
Ok(ref result) if result.to_string() == "None" => None,
_ => panic!("expected None or char for padding"),
}
}

#[cfg(not(feature = "stable"))]
fn get_bool(map: &mut HashMap<String, TokenTree>, key: &str) -> Option<bool> {
let node = match map.remove(key) {
None => return None,
Some(node) => node,
};
let ident = match node {
TokenTree::Ident(ident) => format!("{}", ident),
_ => panic!("expected literal for padding"),
};
Some(syn::parse::boolean(&ident).expect("expected bool for padding"))
}
#[cfg(feature = "stable")]
fn get_bool(map: &mut HashMap<String, Token>, key: &str) -> Option<bool> {
match map.remove(key) {
None => None,
Some(Token::Literal(Lit::Bool(value))) => Some(value),
Some(_) => panic!("expected bool for {}", key),
match syn::parse::<syn::LitBool>(node.into()) {
Ok(result) => Some(result.value),
_ => panic!("expected bool for padding"),
}
}

#[cfg(not(feature = "stable"))]
fn get_bit_order(map: &mut HashMap<String, TokenTree>) -> BitOrder {
let node = match map.remove("bit_order") {
None => return BitOrder::MostSignificantFirst,
Expand All @@ -195,25 +117,13 @@ fn get_bit_order(map: &mut HashMap<String, TokenTree>) -> BitOrder {
_ => panic!("expected {} or {} for bit_order", msb, lsb),
}
}
#[cfg(feature = "stable")]
fn get_bit_order(map: &mut HashMap<String, Token>) -> BitOrder {
let msb = "MostSignificantFirst";
let lsb = "LeastSignificantFirst";
match map.remove("bit_order") {
None => BitOrder::MostSignificantFirst,
Some(Token::Ident(ref ident)) if ident.as_ref() == msb => BitOrder::MostSignificantFirst,
Some(Token::Ident(ref ident)) if ident.as_ref() == lsb => BitOrder::LeastSignificantFirst,
Some(_) => panic!("expected {} or {} for bit_order", msb, lsb),
}
}

fn check_present<T>(hash_map: &HashMap<String, T>, key: &str) {
if !hash_map.contains_key(key) {
panic!("{} is required", key);
}
}

#[cfg(not(feature = "stable"))]
fn get_encoding(mut hash_map: &mut HashMap<String, TokenTree>) -> Encoding {
check_present(&hash_map, "symbols");
let spec = Specification {
Expand All @@ -233,52 +143,22 @@ fn get_encoding(mut hash_map: &mut HashMap<String, TokenTree>) -> Encoding {
};
spec.encoding().unwrap()
}
#[cfg(feature = "stable")]
fn get_encoding(mut hash_map: &mut HashMap<String, Token>) -> Encoding {
check_present(&hash_map, "symbols");
let spec = Specification {
symbols: get_string(&mut hash_map, "symbols"),
bit_order: get_bit_order(&mut hash_map),
check_trailing_bits: get_bool(&mut hash_map, "check_trailing_bits").unwrap_or(true),
padding: get_padding(&mut hash_map),
ignore: get_string(&mut hash_map, "ignore"),
wrap: Wrap {
width: get_usize(&mut hash_map, "wrap_width"),
separator: get_string(&mut hash_map, "wrap_separator"),
},
translate: Translate {
from: get_string(&mut hash_map, "translate_from"),
to: get_string(&mut hash_map, "translate_to"),
},
};
spec.encoding().unwrap()
}

fn check_empty<T>(hash_map: HashMap<String, T>) {
if !hash_map.is_empty() {
panic!("Unexpected keys {:?}", hash_map.keys());
}
}

#[cfg(not(feature = "stable"))]
#[proc_macro]
#[cfg_attr(feature = "stable", proc_macro_hack)]
#[cfg_attr(not(feature = "stable"), proc_macro)]
#[doc(hidden)]
pub fn internal_new_encoding(input: TokenStream) -> TokenStream {
let mut hash_map = parse_map(input.into_iter());
let encoding = get_encoding(&mut hash_map);
check_empty(hash_map);
format!("{:?}", encoding.internal_implementation()).parse().unwrap()
}
#[cfg(feature = "stable")]
proc_macro_expr_impl! {
#[doc(hidden)]
pub fn internal_new_encoding_impl(input: &str) -> String {
let mut hash_map = parse_map(input);
let encoding = get_encoding(&mut hash_map);
check_empty(hash_map);
format!("{:?}", encoding.internal_implementation())
}
}

#[cfg(not(feature = "stable"))]
#[proc_macro]
Expand All @@ -294,8 +174,9 @@ pub fn internal_decode_array(input: TokenStream) -> TokenStream {
let output = encoding.decode(input.as_bytes()).unwrap();
format!("{}: [u8; {}] = {:?};", name, output.len(), output).parse().unwrap()
}
#[cfg(not(feature = "stable"))]
#[proc_macro]

#[cfg_attr(feature = "stable", proc_macro_hack)]
#[cfg_attr(not(feature = "stable"), proc_macro)]
#[doc(hidden)]
pub fn internal_decode_slice(input: TokenStream) -> TokenStream {
let mut hash_map = parse_map(input.into_iter());
Expand All @@ -305,15 +186,3 @@ pub fn internal_decode_slice(input: TokenStream) -> TokenStream {
check_empty(hash_map);
format!("{:?}", encoding.decode(input.as_bytes()).unwrap()).parse().unwrap()
}
#[cfg(feature = "stable")]
proc_macro_expr_impl! {
#[doc(hidden)]
pub fn internal_decode_slice_impl(input: &str) -> String {
let mut hash_map = parse_map(input);
let encoding = get_encoding(&mut hash_map);
check_present(&hash_map, "input");
let input = get_string(&mut hash_map, "input");
check_empty(hash_map);
format!("{:?}", encoding.decode(input.as_bytes()).unwrap())
}
}
22 changes: 11 additions & 11 deletions lib/macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,27 +72,27 @@
#![warn(unused_results)]

#[cfg(feature = "stable")]
#[macro_use]
extern crate proc_macro_hack;

extern crate data_encoding;
#[cfg_attr(feature = "stable", allow(unused_imports))]
#[cfg_attr(feature = "stable", macro_use)]
extern crate data_encoding_macro_internal;

#[cfg(feature = "stable")]
use proc_macro_hack::proc_macro_hack;

#[cfg(not(feature = "stable"))]
#[doc(hidden)]
pub use data_encoding_macro_internal::*;

#[cfg(feature = "stable")]
proc_macro_expr_decl! {
#[doc(hidden)]
internal_new_encoding! => internal_new_encoding_impl
}
#[proc_macro_hack]
#[doc(hidden)]
pub use data_encoding_macro_internal::internal_new_encoding;

#[cfg(feature = "stable")]
proc_macro_expr_decl! {
#[doc(hidden)]
internal_decode_slice! => internal_decode_slice_impl
}
#[proc_macro_hack]
#[doc(hidden)]
pub use data_encoding_macro_internal::internal_decode_slice;

/// Defines a compile-time byte array by decoding a string literal
///
Expand Down
4 changes: 2 additions & 2 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@
//!
//! | Input | `data-encoding` | `rustc` | `base64` | GNU `base64` |
//! | ---------- | --------------- | -------- | -------- | ------------- |
//! | `AAB=` | `Trailing(2)` | `[0, 0]` | `[0, 0]` | `\x00\x00` |
//! | `AAB=` | `Trailing(2)` | `[0, 0]` | `Err(2)` | `\x00\x00` |
//! | `AA\nB=` | `Length(4)` | `[0, 0]` | `Length` | `\x00\x00` |
//! | `AAB` | `Length(0)` | `[0, 0]` | `[0, 0]` | Invalid input |
//! | `AAB` | `Length(0)` | `[0, 0]` | `Err(2)` | Invalid input |
//! | `A\rA\nB=` | `Length(4)` | `[0, 0]` | `Err(1)` | Invalid input |
//! | `-_\r\n` | `Symbol(0)` | `[251]` | `Err(0)` | Invalid input |
//! | `AA==AA==` | `[0, 0]` | `Err` | `Err(2)` | `\x00\x00` |
Expand Down
6 changes: 6 additions & 0 deletions travis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ git clean -fxd
info "Benchmark binary"
./bench.sh
)
( info "Ensure cargo-outdated is installed"
which cargo-outdated >/dev/null || cargo install cargo-outdated

info "Test dependencies"
cargo outdated -w -R --exit-code=1
)

( git clean -fxd

Expand Down