lib.rs 2.1 KB

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