lib.rs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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. extern crate syn;
  12. #[macro_use]
  13. extern crate quote;
  14. extern crate proc_macro;
  15. use proc_macro::TokenStream;
  16. use syn::Body::Enum;
  17. use syn::VariantData::Unit;
  18. #[proc_macro_derive(FromPrimitive)]
  19. pub fn from_primitive(input: TokenStream) -> TokenStream {
  20. let source = input.to_string();
  21. let ast = syn::parse_macro_input(&source).unwrap();
  22. let name = &ast.ident;
  23. let variants = match ast.body {
  24. Enum(ref variants) => variants,
  25. _ => panic!("`FromPrimitive` can be applied only to the enums, {} is not an enum", name)
  26. };
  27. let mut idx = 0;
  28. let variants: Vec<_> = variants.iter()
  29. .map(|variant| {
  30. let ident = &variant.ident;
  31. match variant.data {
  32. Unit => (),
  33. _ => {
  34. panic!("`FromPrimitive` can be applied only to unitary enums, {}::{} is either struct or tuple", name, ident)
  35. },
  36. }
  37. if let Some(val) = variant.discriminant {
  38. idx = val.value;
  39. }
  40. let tt = quote!(#idx => Some(#name::#ident));
  41. idx += 1;
  42. tt
  43. })
  44. .collect();
  45. let res = quote! {
  46. impl ::num::traits::FromPrimitive for #name {
  47. fn from_i64(n: i64) -> Option<Self> {
  48. Self::from_u64(n as u64)
  49. }
  50. fn from_u64(n: u64) -> Option<Self> {
  51. match n {
  52. #(variants,)*
  53. _ => None,
  54. }
  55. }
  56. }
  57. };
  58. res.to_string().parse().unwrap()
  59. }
  60. #[proc_macro_derive(ToPrimitive)]
  61. pub fn to_primitive(input: TokenStream) -> TokenStream {
  62. let source = input.to_string();
  63. let ast = syn::parse_macro_input(&source).unwrap();
  64. let name = &ast.ident;
  65. let variants = match ast.body {
  66. Enum(ref variants) => variants,
  67. _ => panic!("`ToPrimitive` can be applied only to the enums, {} is not an enum", name)
  68. };
  69. let mut idx = 0;
  70. let variants: Vec<_> = variants.iter()
  71. .map(|variant| {
  72. let ident = &variant.ident;
  73. match variant.data {
  74. Unit => (),
  75. _ => {
  76. panic!("`ToPrimitive` can be applied only to unitary enums, {}::{} is either struct or tuple", name, ident)
  77. },
  78. }
  79. if let Some(val) = variant.discriminant {
  80. idx = val.value;
  81. }
  82. let tt = quote!(#name::#ident => #idx);
  83. idx += 1;
  84. tt
  85. })
  86. .collect();
  87. let res = quote! {
  88. impl ::num::traits::ToPrimitive for #name {
  89. fn to_i64(&self) -> Option<i64> {
  90. self.to_u64().map(|x| x as i64)
  91. }
  92. fn to_u64(&self) -> Option<u64> {
  93. Some(match *self {
  94. #(variants,)*
  95. })
  96. }
  97. }
  98. };
  99. res.to_string().parse().unwrap()
  100. }