lib.rs 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. // Copyright 2012-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. #![crate_type = "proc-macro"]
  11. #![feature(proc_macro, proc_macro_lib)]
  12. extern crate syn;
  13. #[macro_use]
  14. extern crate quote;
  15. extern crate proc_macro;
  16. use proc_macro::TokenStream;
  17. use syn::Body::Enum;
  18. use syn::VariantData::Unit;
  19. #[proc_macro_derive(FromPrimitive)]
  20. pub fn from_primitive(input: TokenStream) -> TokenStream {
  21. let source = input.to_string();
  22. let ast = syn::parse_macro_input(&source).unwrap();
  23. let name = &ast.ident;
  24. let variants = match ast.body {
  25. Enum(ref variants) => variants,
  26. _ => panic!("`FromPrimitive` can be applied only to the enums, {} is not an enum", name)
  27. };
  28. let mut idx = 0;
  29. let variants: Vec<_> = variants.iter()
  30. .map(|variant| {
  31. let ident = &variant.ident;
  32. match variant.data {
  33. Unit => (),
  34. _ => {
  35. panic!("`FromPrimitive` can be applied only to unitary enums, {}::{} is either struct or tuple", name, ident)
  36. },
  37. }
  38. if let Some(val) = variant.discriminant {
  39. idx = val.value;
  40. }
  41. let tt = quote!(#idx => Some(#name::#ident));
  42. idx += 1;
  43. tt
  44. })
  45. .collect();
  46. let res = quote! {
  47. impl ::num::traits::FromPrimitive for #name {
  48. fn from_i64(n: i64) -> Option<Self> {
  49. Self::from_u64(n as u64)
  50. }
  51. fn from_u64(n: u64) -> Option<Self> {
  52. match n {
  53. #(variants,)*
  54. _ => None,
  55. }
  56. }
  57. }
  58. };
  59. res.to_string().parse().unwrap()
  60. }