From 1f408cc58a3a4ef24946828f20dcfdf14cd2fd6e Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 28 Jan 2016 20:23:40 +0100 Subject: [PATCH] Support byte string keys in phf_macros (fixes #76) Because of https://github.com/rust-lang/rust/issues/31260, a cast must be inserted explicitly instead of letting rustc implicitly coercing the type. --- phf_macros/src/lib.rs | 56 +++++++++++++++++++++++----------------- phf_macros/tests/test.rs | 5 ++++ 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/phf_macros/src/lib.rs b/phf_macros/src/lib.rs index fc5b532d..5ac953a0 100644 --- a/phf_macros/src/lib.rs +++ b/phf_macros/src/lib.rs @@ -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; @@ -162,9 +164,9 @@ fn parse_map(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { 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) { @@ -201,9 +203,9 @@ fn parse_set(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { 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 { @@ -225,34 +227,40 @@ fn parse_set(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option> { Some(entries) } -fn parse_key(cx: &mut ExtCtxt, e: &Expr) -> Option { +fn parse_key(cx: &mut ExtCtxt, e: P) -> Option<(Key, P)> { 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 @@ -271,7 +279,7 @@ fn parse_key(cx: &mut ExtCtxt, e: &Expr) -> Option { 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"); diff --git a/phf_macros/tests/test.rs b/phf_macros/tests/test.rs index 1670eef0..c10ed301 100644 --- a/phf_macros/tests/test.rs +++ b/phf_macros/tests/test.rs @@ -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!(