getters.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. use indexmap::IndexMap;
  2. use proc_macro2::{Span, TokenStream};
  3. use quote::{quote, TokenStreamExt};
  4. use syn::{
  5. self, Fields, FieldsNamed, Generics, Ident, Item, ItemStruct, ItemUnion, Path, Type, TypePath,
  6. Visibility,
  7. };
  8. pub struct GetterList<'a> {
  9. slf: Ident,
  10. item_fields: IndexMap<Ident, (&'a Item, &'a FieldsNamed)>,
  11. }
  12. impl<'a> GetterList<'a> {
  13. pub fn new(items: &'a [Item]) -> GetterList<'a> {
  14. let item_fields = items
  15. .iter()
  16. .filter_map(|item| {
  17. unpack_item(item).map(|(ident, _generics, fields)| (ident.clone(), (item, fields)))
  18. })
  19. .collect();
  20. GetterList {
  21. slf: Ident::new("self", Span::call_site()),
  22. item_fields,
  23. }
  24. }
  25. pub fn iter(&self) -> impl Iterator<Item = (&'a Item, Vec<Getter<'_>>)> {
  26. self.item_fields
  27. .values()
  28. .map(move |(item, fields)| (*item, self.getters(&self.slf, fields)))
  29. }
  30. fn getters(&self, ident: &'a Ident, fields: &'a FieldsNamed) -> Vec<Getter<'a>> {
  31. let mut getters = Vec::new();
  32. for field in &fields.named {
  33. if let Visibility::Inherited = field.vis {
  34. continue;
  35. }
  36. let field_ident = field.ident.as_ref().unwrap();
  37. let field_s = field_ident.to_string();
  38. // FIXME: bindgen generates fields named `_bitfield_N` for bitfields. If a type T has
  39. // two or more unions with bitfields, the getters for the bitfields - generated in impl
  40. // T - will clash. To avoid that we skip getters for bitfields altogether for now.
  41. // See sk_reuseport_md for an example where the clash happens.
  42. if field_s.starts_with("_bitfield") {
  43. continue;
  44. }
  45. if field_s.starts_with("__bindgen_anon") {
  46. let field_ty_ident = match &field.ty {
  47. Type::Path(TypePath {
  48. path: Path { segments, .. },
  49. ..
  50. }) => &segments.first().unwrap().ident,
  51. _ => panic!(),
  52. };
  53. let sub_fields = self
  54. .item_fields
  55. .get(field_ty_ident)
  56. .unwrap_or_else(|| panic!("{}", field_ty_ident.to_string()))
  57. .1;
  58. getters.extend(self.getters(field_ident, sub_fields).drain(..).map(
  59. |mut getter| {
  60. getter.prefix.insert(0, ident);
  61. getter
  62. },
  63. ));
  64. } else {
  65. getters.push(Getter {
  66. ident: field_ident,
  67. prefix: vec![ident],
  68. ty: &field.ty,
  69. });
  70. }
  71. }
  72. getters
  73. }
  74. }
  75. pub fn generate_getters_for_items(
  76. items: &[Item],
  77. gen_getter: impl Fn(&Getter<'_>) -> TokenStream,
  78. ) -> TokenStream {
  79. let mut tokens = TokenStream::new();
  80. tokens.append_all(GetterList::new(items).iter().map(|(item, getters)| {
  81. let getters = getters.iter().map(&gen_getter);
  82. let (ident, generics, _) = unpack_item(item).unwrap();
  83. quote! {
  84. impl#generics #ident#generics {
  85. #(#getters)*
  86. }
  87. }
  88. }));
  89. tokens
  90. }
  91. pub fn read_getter(getter: &Getter<'_>, read_fn: &Path) -> TokenStream {
  92. let ident = getter.ident;
  93. let ty = getter.ty;
  94. let prefix = &getter.prefix;
  95. match ty {
  96. Type::Ptr(_) => {
  97. quote! {
  98. pub fn #ident(&self) -> Option<#ty> {
  99. let v = unsafe { #read_fn(&#(#prefix).*.#ident) }.ok()?;
  100. if v.is_null() {
  101. None
  102. } else {
  103. Some(v)
  104. }
  105. }
  106. }
  107. }
  108. _ => {
  109. quote! {
  110. pub fn #ident(&self) -> Option<#ty> {
  111. unsafe { #read_fn(&#(#prefix).*.#ident) }.ok()
  112. }
  113. }
  114. }
  115. }
  116. }
  117. pub struct Getter<'a> {
  118. pub ident: &'a Ident,
  119. pub prefix: Vec<&'a Ident>,
  120. pub ty: &'a Type,
  121. }
  122. fn unpack_item(item: &Item) -> Option<(&Ident, &Generics, &FieldsNamed)> {
  123. match item {
  124. Item::Struct(ItemStruct {
  125. ident,
  126. generics,
  127. fields: Fields::Named(fields),
  128. ..
  129. })
  130. | Item::Union(ItemUnion {
  131. ident,
  132. generics,
  133. fields,
  134. ..
  135. }) => Some((ident, generics, fields)),
  136. _ => None,
  137. }
  138. }