Skip to content

Commit

Permalink
Support byte string keys in phf_macros (fixes rust-phf#76)
Browse files Browse the repository at this point in the history
Because of rust-lang/rust#31260, a cast must be inserted
explicitly instead of letting rustc implicitly coercing the type.
  • Loading branch information
nox committed Jan 28, 2016
1 parent ae5ee38 commit 1f408cc
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 24 deletions.
56 changes: 32 additions & 24 deletions phf_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ extern crate phf_generator;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use syntax::ast::{self, TokenTree, Expr, ExprLit, ExprVec};
use syntax::ast::{self, Expr, ExprLit, ExprVec, MutImmutable, TokenTree, TyVec};
use syntax::codemap::{Span, Spanned};
use syntax::ext::base::{DummyResult, ExtCtxt, MacResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse;
use syntax::parse::token::{InternedString, Comma, Eof, FatArrow};
use syntax::print::pprust;
use syntax::ptr::P;
use rustc_plugin::Registry;
use phf_generator::HashState;
use std::env;
Expand Down Expand Up @@ -162,9 +164,9 @@ fn parse_map(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
let mut bad = false;
while parser.token != Eof {
let key = cx.expander().fold_expr(parser.parse_expr().unwrap());
let key_contents = parse_key(cx, &*key).unwrap_or_else(|| {
let (key_contents, key) = parse_key(cx, key.clone()).unwrap_or_else(|| {
bad = true;
Key::Str(InternedString::new(""))
(Key::Str(InternedString::new("")), key)
});

if !parser.eat(&FatArrow) {
Expand Down Expand Up @@ -201,9 +203,9 @@ fn parse_set(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
let mut bad = false;
while parser.token != Eof {
let key = cx.expander().fold_expr(parser.parse_expr().unwrap());
let key_contents = parse_key(cx, &*key).unwrap_or_else(|| {
let (key_contents, key) = parse_key(cx, key.clone()).unwrap_or_else(|| {
bad = true;
Key::Str(InternedString::new(""))
(Key::Str(InternedString::new("")), key)
});

entries.push(Entry {
Expand All @@ -225,34 +227,40 @@ fn parse_set(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
Some(entries)
}

fn parse_key(cx: &mut ExtCtxt, e: &Expr) -> Option<Key> {
fn parse_key(cx: &mut ExtCtxt, e: P<Expr>) -> Option<(Key, P<Expr>)> {
match e.node {
ExprLit(ref lit) => {
match lit.node {
ast::LitStr(ref s, _) => Some(Key::Str(s.clone())),
ast::LitByteStr(ref b) => Some(Key::Binary(b.clone())),
ast::LitByte(b) => Some(Key::U8(b)),
ast::LitChar(c) => Some(Key::Char(c)),
ast::LitInt(i, ast::SignedIntLit(ast::TyI8, ast::Plus)) => Some(Key::I8(i as i8)),
ast::LitStr(ref s, _) => Some((Key::Str(s.clone()), e.clone())),
ast::LitByteStr(ref b) => {
let u8_type = cx.ty_path(cx.path_ident(e.span, cx.ident_of("u8")));
let array_type = cx.ty(e.span, TyVec(u8_type));
let slice_type = cx.ty_rptr(e.span, array_type, None, MutImmutable);
let key = cx.expr_cast(e.span, e.clone(), slice_type);
Some((Key::Binary(b.clone()), key))
},
ast::LitByte(b) => Some((Key::U8(b), e.clone())),
ast::LitChar(c) => Some((Key::Char(c), e.clone())),
ast::LitInt(i, ast::SignedIntLit(ast::TyI8, ast::Plus)) => Some((Key::I8(i as i8), e.clone())),
ast::LitInt(i, ast::SignedIntLit(ast::TyI8, ast::Minus)) =>
Some(Key::I8(-(i as i8))),
Some((Key::I8(-(i as i8)), e.clone())),
ast::LitInt(i, ast::SignedIntLit(ast::TyI16, ast::Plus)) =>
Some(Key::I16(i as i16)),
Some((Key::I16(i as i16), e.clone())),
ast::LitInt(i, ast::SignedIntLit(ast::TyI16, ast::Minus)) =>
Some(Key::I16(-(i as i16))),
Some((Key::I16(-(i as i16)), e.clone())),
ast::LitInt(i, ast::SignedIntLit(ast::TyI32, ast::Plus)) =>
Some(Key::I32(i as i32)),
Some((Key::I32(i as i32), e.clone())),
ast::LitInt(i, ast::SignedIntLit(ast::TyI32, ast::Minus)) =>
Some(Key::I32(-(i as i32))),
Some((Key::I32(-(i as i32)), e.clone())),
ast::LitInt(i, ast::SignedIntLit(ast::TyI64, ast::Plus)) =>
Some(Key::I64(i as i64)),
Some((Key::I64(i as i64), e.clone())),
ast::LitInt(i, ast::SignedIntLit(ast::TyI64, ast::Minus)) =>
Some(Key::I64(-(i as i64))),
ast::LitInt(i, ast::UnsignedIntLit(ast::TyU8)) => Some(Key::U8(i as u8)),
ast::LitInt(i, ast::UnsignedIntLit(ast::TyU16)) => Some(Key::U16(i as u16)),
ast::LitInt(i, ast::UnsignedIntLit(ast::TyU32)) => Some(Key::U32(i as u32)),
ast::LitInt(i, ast::UnsignedIntLit(ast::TyU64)) => Some(Key::U64(i as u64)),
ast::LitBool(b) => Some(Key::Bool(b)),
Some((Key::I64(-(i as i64)), e.clone())),
ast::LitInt(i, ast::UnsignedIntLit(ast::TyU8)) => Some((Key::U8(i as u8), e.clone())),
ast::LitInt(i, ast::UnsignedIntLit(ast::TyU16)) => Some((Key::U16(i as u16), e.clone())),
ast::LitInt(i, ast::UnsignedIntLit(ast::TyU32)) => Some((Key::U32(i as u32), e.clone())),
ast::LitInt(i, ast::UnsignedIntLit(ast::TyU64)) => Some((Key::U64(i as u64), e.clone())),
ast::LitBool(b) => Some((Key::Bool(b), e.clone())),
_ => {
cx.span_err(e.span, "unsupported literal type");
None
Expand All @@ -271,7 +279,7 @@ fn parse_key(cx: &mut ExtCtxt, e: &Expr) -> Option<Key> {
None
}).collect();
if bytes.iter().all(|x| x.is_some()) {
Some(Key::Binary(std::rc::Rc::new(bytes.iter().map(|x| x.unwrap()).collect())))
Some((Key::Binary(std::rc::Rc::new(bytes.iter().map(|x| x.unwrap()).collect())), e.clone()))
} else {
cx.span_err(e.span,
"not all elements of an expected u8 array literal were u8 literals");
Expand Down
5 changes: 5 additions & 0 deletions phf_macros/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ mod map {
"foo" => 10
);

#[allow(dead_code)]
static BYTE_STRING_KEY: phf::Map<&'static [u8], &'static str> = phf_map!(
b"camembert" => "delicious",
);

#[test]
fn test_two() {
static MAP: phf::Map<&'static str, isize> = phf_map!(
Expand Down

0 comments on commit 1f408cc

Please sign in to comment.