zeroable.rs 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // SPDX-License-Identifier: GPL-2.0
  2. use crate::helpers::{parse_generics, Generics};
  3. use proc_macro::{TokenStream, TokenTree};
  4. pub(crate) fn derive(input: TokenStream) -> TokenStream {
  5. let (
  6. Generics {
  7. impl_generics,
  8. decl_generics: _,
  9. ty_generics,
  10. },
  11. mut rest,
  12. ) = parse_generics(input);
  13. // This should be the body of the struct `{...}`.
  14. let last = rest.pop();
  15. // Now we insert `Zeroable` as a bound for every generic parameter in `impl_generics`.
  16. let mut new_impl_generics = Vec::with_capacity(impl_generics.len());
  17. // Are we inside of a generic where we want to add `Zeroable`?
  18. let mut in_generic = !impl_generics.is_empty();
  19. // Have we already inserted `Zeroable`?
  20. let mut inserted = false;
  21. // Level of `<>` nestings.
  22. let mut nested = 0;
  23. for tt in impl_generics {
  24. match &tt {
  25. // If we find a `,`, then we have finished a generic/constant/lifetime parameter.
  26. TokenTree::Punct(p) if nested == 0 && p.as_char() == ',' => {
  27. if in_generic && !inserted {
  28. new_impl_generics.extend(quote! { : ::kernel::init::Zeroable });
  29. }
  30. in_generic = true;
  31. inserted = false;
  32. new_impl_generics.push(tt);
  33. }
  34. // If we find `'`, then we are entering a lifetime.
  35. TokenTree::Punct(p) if nested == 0 && p.as_char() == '\'' => {
  36. in_generic = false;
  37. new_impl_generics.push(tt);
  38. }
  39. TokenTree::Punct(p) if nested == 0 && p.as_char() == ':' => {
  40. new_impl_generics.push(tt);
  41. if in_generic {
  42. new_impl_generics.extend(quote! { ::kernel::init::Zeroable + });
  43. inserted = true;
  44. }
  45. }
  46. TokenTree::Punct(p) if p.as_char() == '<' => {
  47. nested += 1;
  48. new_impl_generics.push(tt);
  49. }
  50. TokenTree::Punct(p) if p.as_char() == '>' => {
  51. assert!(nested > 0);
  52. nested -= 1;
  53. new_impl_generics.push(tt);
  54. }
  55. _ => new_impl_generics.push(tt),
  56. }
  57. }
  58. assert_eq!(nested, 0);
  59. if in_generic && !inserted {
  60. new_impl_generics.extend(quote! { : ::kernel::init::Zeroable });
  61. }
  62. quote! {
  63. ::kernel::__derive_zeroable!(
  64. parse_input:
  65. @sig(#(#rest)*),
  66. @impl_generics(#(#new_impl_generics)*),
  67. @ty_generics(#(#ty_generics)*),
  68. @body(#last),
  69. );
  70. }
  71. }