Auto merge of #228 - rust-num:fix/num-macros, r=cuviper

Fix `num-macros` `FromPrimitive` implementation

Current solution follow syntax proposed in rust-lang/rfcs#1681.

Tracking issue rust-lang/rust#35900

Close #227

Code broken after change:

- [ ] https://github.com/kdar/gameboy-rs
- [ ] https://github.com/lemonrock/mbedtls
- [ ] https://github.com/timorantalaiho/kelaa
- [ ] https://github.com/dylanede/cef-rs
- [ ] https://github.com/klutzy/aheui-llvm
- [ ] https://github.com/pcwalton/rust-media
- [ ] https://github.com/PistonDevelopers/hematite_server
This commit is contained in:
Homu 2016-09-30 14:58:47 +09:00
commit 019c136b8c
9 changed files with 270 additions and 0 deletions

View File

@ -5,6 +5,7 @@ set -ex
cargo bench --verbose cargo bench --verbose
cargo test --verbose --manifest-path=macros/Cargo.toml cargo test --verbose --manifest-path=macros/Cargo.toml
cargo test --verbose --manifest-path=derive/Cargo.toml
# Build test for the serde feature # Build test for the serde feature
cargo build --verbose --features "serde" cargo build --verbose --features "serde"

27
derive/Cargo.toml Normal file
View File

@ -0,0 +1,27 @@
[package]
authors = ["The Rust Project Developers"]
description = "Numeric syntax extensions"
documentation = "http://rust-num.github.io/num"
homepage = "https://github.com/rust-num/num"
keywords = ["mathematics", "numerics"]
license = "MIT/Apache-2.0"
name = "num-derive"
repository = "https://github.com/rust-num/num"
version = "0.1.33"
[dependencies]
quote = "0.1.3"
syn = "0.7.0"
[dev-dependencies]
compiletest_rs = "0.2.2"
[dev-dependencies.num]
path = ".."
version = "0.1"
[lib]
crate-type = ["rustc-macro"]
name = "num_derive"
rustc-macro = true
test = false

76
derive/src/lib.rs Normal file
View File

@ -0,0 +1,76 @@
// Copyright 2012-2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_type = "rustc-macro"]
#![feature(rustc_macro, rustc_macro_lib)]
extern crate syn;
#[macro_use]
extern crate quote;
extern crate rustc_macro;
use rustc_macro::TokenStream;
use syn::Body::Enum;
use syn::VariantData::Unit;
#[rustc_macro_derive(FromPrimitive)]
pub fn from_primitive(input: TokenStream) -> TokenStream {
let source = input.to_string();
let ast = syn::parse_macro_input(&source).unwrap();
let name = &ast.ident;
let variants = match ast.body {
Enum(ref variants) => variants,
_ => {
panic!("`FromPrimitive` can be applied only to the enums, {} is not an enum",
name)
}
};
let mut idx = 0;
let variants: Vec<_> = variants.iter()
.map(|variant| {
let ident = &variant.ident;
match variant.data {
Unit => (),
_ => {
panic!("`FromPrimitive` can be applied only to unitary enums, {}::{} is either struct or tuple", name, ident)
},
}
if let Some(val) = variant.discriminant {
idx = val.value;
}
let tt = quote!(#idx => Some(#name::#ident));
idx += 1;
tt
})
.collect();
let res = quote! {
#ast
impl ::num::traits::FromPrimitive for #name {
fn from_i64(n: i64) -> Option<Self> {
Self::from_u64(n as u64)
}
fn from_u64(n: u64) -> Option<Self> {
match n {
#(variants,)*
_ => None,
}
}
}
};
res.to_string().parse().unwrap()
}

View File

@ -0,0 +1,25 @@
// Copyright 2013-2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_macro)]
extern crate num;
#[macro_use]
extern crate num_derive;
#[derive(Debug, PartialEq, FromPrimitive)] //~ ERROR
struct Color {
r: u8,
g: u8,
b: u8,
}
fn main() {}

View File

@ -0,0 +1,24 @@
// Copyright 2013-2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_macro)]
extern crate num;
#[macro_use]
extern crate num_derive;
#[derive(Debug, PartialEq, FromPrimitive)] //~ ERROR
enum Color {
Rgb(u8, u8, u8),
Hsv(u8, u8, u8),
}
fn main() {}

View File

@ -0,0 +1,25 @@
extern crate compiletest_rs as compiletest;
use std::path::PathBuf;
use std::env::var;
fn run_mode(mode: &'static str) {
let mut config = compiletest::default_config();
let cfg_mode = mode.parse().ok().expect("Invalid mode");
config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps/".to_owned());
if let Ok(name) = var::<&str>("TESTNAME") {
let s : String = name.to_owned();
config.filter = Some(s)
}
config.mode = cfg_mode;
config.src_base = PathBuf::from(format!("tests/{}", mode));
compiletest::run_tests(&config);
}
#[test]
fn compile_test() {
run_mode("compile-fail");
}

View File

@ -0,0 +1,26 @@
// Copyright 2013-2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_macro)]
extern crate num;
#[macro_use]
extern crate num_derive;
#[derive(Debug, PartialEq, FromPrimitive)]
enum Color {}
#[test]
fn test_empty_enum() {
let v: [Option<Color>; 1] = [num::FromPrimitive::from_u64(0)];
assert_eq!(v, [None]);
}

33
derive/tests/trivial.rs Normal file
View File

@ -0,0 +1,33 @@
// Copyright 2013-2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_macro)]
extern crate num;
#[macro_use]
extern crate num_derive;
#[derive(Debug, PartialEq, FromPrimitive)]
enum Color {
Red,
Blue,
Green,
}
#[test]
fn test_from_primitive_for_trivial_case() {
let v: [Option<Color>; 4] = [num::FromPrimitive::from_u64(0),
num::FromPrimitive::from_u64(1),
num::FromPrimitive::from_u64(2),
num::FromPrimitive::from_u64(3)];
assert_eq!(v,
[Some(Color::Red), Some(Color::Blue), Some(Color::Green), None]);
}

View File

@ -0,0 +1,33 @@
// Copyright 2013-2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_macro)]
extern crate num;
#[macro_use]
extern crate num_derive;
#[derive(Debug, PartialEq, FromPrimitive)]
enum Color {
Red,
Blue = 5,
Green,
}
#[test]
fn test_from_primitive_for_enum_with_custom_value() {
let v: [Option<Color>; 4] = [num::FromPrimitive::from_u64(0),
num::FromPrimitive::from_u64(5),
num::FromPrimitive::from_u64(6),
num::FromPrimitive::from_u64(3)];
assert_eq!(v,
[Some(Color::Red), Some(Color::Blue), Some(Color::Green), None]);
}