Skip to content

Commit 73a2dfd

Browse files
committed
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.
2 parents 26af99c + 5f3a3b0 commit 73a2dfd

File tree

7 files changed

+114
-2
lines changed

7 files changed

+114
-2
lines changed

derive/src/lib.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,51 @@ pub fn from_primitive(input: TokenStream) -> TokenStream {
6868

6969
res.to_string().parse().unwrap()
7070
}
71+
72+
#[proc_macro_derive(ToPrimitive)]
73+
pub fn to_primitive(input: TokenStream) -> TokenStream {
74+
let source = input.to_string();
75+
76+
let ast = syn::parse_macro_input(&source).unwrap();
77+
let name = &ast.ident;
78+
79+
let variants = match ast.body {
80+
Enum(ref variants) => variants,
81+
_ => panic!("`ToPrimitive` can be applied only to the enums, {} is not an enum", name)
82+
};
83+
84+
let mut idx = 0;
85+
let variants: Vec<_> = variants.iter()
86+
.map(|variant| {
87+
let ident = &variant.ident;
88+
match variant.data {
89+
Unit => (),
90+
_ => {
91+
panic!("`ToPrimitive` can be applied only to unitary enums, {}::{} is either struct or tuple", name, ident)
92+
},
93+
}
94+
if let Some(val) = variant.discriminant {
95+
idx = val.value;
96+
}
97+
let tt = quote!(#name::#ident => #idx);
98+
idx += 1;
99+
tt
100+
})
101+
.collect();
102+
103+
let res = quote! {
104+
impl ::num::traits::ToPrimitive for #name {
105+
fn to_i64(&self) -> Option<i64> {
106+
self.to_u64().map(|x| x as i64)
107+
}
108+
109+
fn to_u64(&self) -> Option<u64> {
110+
Some(match *self {
111+
#(variants,)*
112+
})
113+
}
114+
}
115+
};
116+
117+
res.to_string().parse().unwrap()
118+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
extern crate num;
12+
#[macro_use]
13+
extern crate num_derive;
14+
15+
#[derive(Debug, PartialEq, ToPrimitive)] //~ ERROR
16+
struct Color {
17+
r: u8,
18+
g: u8,
19+
b: u8,
20+
}
21+
22+
fn main() {}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
extern crate num;
12+
#[macro_use]
13+
extern crate num_derive;
14+
15+
#[derive(Debug, PartialEq, ToPrimitive)] //~ ERROR
16+
enum Color {
17+
Rgb(u8, u8, u8),
18+
Hsv(u8, u8, u8),
19+
}
20+
21+
fn main() {}

derive/tests/empty_enum.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ extern crate num;
1212
#[macro_use]
1313
extern crate num_derive;
1414

15-
#[derive(Debug, PartialEq, FromPrimitive)]
15+
#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
1616
enum Color {}
1717

1818
#[test]

derive/tests/trivial.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ extern crate num;
1212
#[macro_use]
1313
extern crate num_derive;
1414

15-
#[derive(Debug, PartialEq, FromPrimitive)]
15+
#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
1616
enum Color {
1717
Red,
1818
Blue,
@@ -29,3 +29,24 @@ fn test_from_primitive_for_trivial_case() {
2929
assert_eq!(v,
3030
[Some(Color::Red), Some(Color::Blue), Some(Color::Green), None]);
3131
}
32+
33+
#[test]
34+
fn test_to_primitive_for_trivial_case() {
35+
let v: [Option<u64>; 3] = [num::ToPrimitive::to_u64(&Color::Red),
36+
num::ToPrimitive::to_u64(&Color::Blue),
37+
num::ToPrimitive::to_u64(&Color::Green)];
38+
39+
assert_eq!(v, [Some(0), Some(1), Some(2)]);
40+
}
41+
42+
#[test]
43+
fn test_reflexive_for_trivial_case() {
44+
let before: [u64; 3] = [0, 1, 2];
45+
let after: Vec<Option<u64>> = before.iter()
46+
.map(|&x| -> Option<Color> { num::FromPrimitive::from_u64(x) })
47+
.map(|x| x.and_then(|x| num::ToPrimitive::to_u64(&x)))
48+
.collect();
49+
let before = before.into_iter().cloned().map(Some).collect::<Vec<_>>();
50+
51+
assert_eq!(before, after);
52+
}

0 commit comments

Comments
 (0)