Merge #314
314: Derive ToPrimitive for enums r=cuviper I had to double the compile fail tests, as they will bail on the first error. I have some ideas for more complex to/from primitive derives (with inner values that implement to/from primitive), but I'll save those for a future PR.
This commit is contained in:
commit
73a2dfd647
|
@ -68,3 +68,51 @@ pub fn from_primitive(input: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
res.to_string().parse().unwrap()
|
res.to_string().parse().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(ToPrimitive)]
|
||||||
|
pub fn to_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!("`ToPrimitive` 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!("`ToPrimitive` 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!(#name::#ident => #idx);
|
||||||
|
idx += 1;
|
||||||
|
tt
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let res = quote! {
|
||||||
|
impl ::num::traits::ToPrimitive for #name {
|
||||||
|
fn to_i64(&self) -> Option<i64> {
|
||||||
|
self.to_u64().map(|x| x as i64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_u64(&self) -> Option<u64> {
|
||||||
|
Some(match *self {
|
||||||
|
#(variants,)*
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
res.to_string().parse().unwrap()
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
extern crate num;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate num_derive;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, ToPrimitive)] //~ ERROR
|
||||||
|
struct Color {
|
||||||
|
r: u8,
|
||||||
|
g: u8,
|
||||||
|
b: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,21 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
extern crate num;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate num_derive;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, ToPrimitive)] //~ ERROR
|
||||||
|
enum Color {
|
||||||
|
Rgb(u8, u8, u8),
|
||||||
|
Hsv(u8, u8, u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -12,7 +12,7 @@ extern crate num;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate num_derive;
|
extern crate num_derive;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, FromPrimitive)]
|
#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
|
||||||
enum Color {}
|
enum Color {}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -12,7 +12,7 @@ extern crate num;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate num_derive;
|
extern crate num_derive;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, FromPrimitive)]
|
#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
|
||||||
enum Color {
|
enum Color {
|
||||||
Red,
|
Red,
|
||||||
Blue,
|
Blue,
|
||||||
|
@ -29,3 +29,24 @@ fn test_from_primitive_for_trivial_case() {
|
||||||
assert_eq!(v,
|
assert_eq!(v,
|
||||||
[Some(Color::Red), Some(Color::Blue), Some(Color::Green), None]);
|
[Some(Color::Red), Some(Color::Blue), Some(Color::Green), None]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_primitive_for_trivial_case() {
|
||||||
|
let v: [Option<u64>; 3] = [num::ToPrimitive::to_u64(&Color::Red),
|
||||||
|
num::ToPrimitive::to_u64(&Color::Blue),
|
||||||
|
num::ToPrimitive::to_u64(&Color::Green)];
|
||||||
|
|
||||||
|
assert_eq!(v, [Some(0), Some(1), Some(2)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_reflexive_for_trivial_case() {
|
||||||
|
let before: [u64; 3] = [0, 1, 2];
|
||||||
|
let after: Vec<Option<u64>> = before.iter()
|
||||||
|
.map(|&x| -> Option<Color> { num::FromPrimitive::from_u64(x) })
|
||||||
|
.map(|x| x.and_then(|x| num::ToPrimitive::to_u64(&x)))
|
||||||
|
.collect();
|
||||||
|
let before = before.into_iter().cloned().map(Some).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
assert_eq!(before, after);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue