pb_attrs.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. #![allow(clippy::all)]
  2. use crate::{symbol::*, ASTResult};
  3. use proc_macro2::{Group, Span, TokenStream, TokenTree};
  4. use quote::ToTokens;
  5. use syn::{
  6. self,
  7. parse::{self, Parse},
  8. Meta::{List, NameValue, Path},
  9. NestedMeta::{Lit, Meta},
  10. };
  11. #[allow(dead_code)]
  12. pub struct PBAttrsContainer {
  13. name: String,
  14. pb_struct_type: Option<syn::Type>,
  15. pb_enum_type: Option<syn::Type>,
  16. }
  17. impl PBAttrsContainer {
  18. /// Extract out the `#[pb(...)]` attributes from an item.
  19. pub fn from_ast(ast_result: &ASTResult, item: &syn::DeriveInput) -> Self {
  20. let mut pb_struct_type = ASTAttr::none(ast_result, PB_STRUCT);
  21. let mut pb_enum_type = ASTAttr::none(ast_result, PB_ENUM);
  22. for meta_item in item
  23. .attrs
  24. .iter()
  25. .flat_map(|attr| get_pb_meta_items(ast_result, attr))
  26. .flatten()
  27. {
  28. match &meta_item {
  29. // Parse `#[pb(struct = "Type")]
  30. Meta(NameValue(m)) if m.path == PB_STRUCT => {
  31. if let Ok(into_ty) = parse_lit_into_ty(ast_result, PB_STRUCT, &m.lit) {
  32. pb_struct_type.set_opt(&m.path, Some(into_ty));
  33. }
  34. },
  35. // Parse `#[pb(enum = "Type")]
  36. Meta(NameValue(m)) if m.path == PB_ENUM => {
  37. if let Ok(into_ty) = parse_lit_into_ty(ast_result, PB_ENUM, &m.lit) {
  38. pb_enum_type.set_opt(&m.path, Some(into_ty));
  39. }
  40. },
  41. Meta(meta_item) => {
  42. let path = meta_item
  43. .path()
  44. .into_token_stream()
  45. .to_string()
  46. .replace(' ', "");
  47. ast_result.error_spanned_by(
  48. meta_item.path(),
  49. format!("unknown container attribute `{}`", path),
  50. );
  51. },
  52. Lit(lit) => {
  53. ast_result.error_spanned_by(lit, "unexpected literal in container attribute");
  54. },
  55. }
  56. }
  57. match &item.data {
  58. syn::Data::Struct(_) => {
  59. pb_struct_type.set_if_none(default_pb_type(&ast_result, &item.ident));
  60. },
  61. syn::Data::Enum(_) => {
  62. pb_enum_type.set_if_none(default_pb_type(&ast_result, &item.ident));
  63. },
  64. _ => {},
  65. }
  66. PBAttrsContainer {
  67. name: item.ident.to_string(),
  68. pb_struct_type: pb_struct_type.get(),
  69. pb_enum_type: pb_enum_type.get(),
  70. }
  71. }
  72. pub fn pb_struct_type(&self) -> Option<&syn::Type> {
  73. self.pb_struct_type.as_ref()
  74. }
  75. pub fn pb_enum_type(&self) -> Option<&syn::Type> {
  76. self.pb_enum_type.as_ref()
  77. }
  78. }
  79. pub struct ASTAttr<'c, T> {
  80. ast_result: &'c ASTResult,
  81. name: Symbol,
  82. tokens: TokenStream,
  83. value: Option<T>,
  84. }
  85. impl<'c, T> ASTAttr<'c, T> {
  86. pub(crate) fn none(ast_result: &'c ASTResult, name: Symbol) -> Self {
  87. ASTAttr {
  88. ast_result,
  89. name,
  90. tokens: TokenStream::new(),
  91. value: None,
  92. }
  93. }
  94. pub(crate) fn set<A: ToTokens>(&mut self, obj: A, value: T) {
  95. let tokens = obj.into_token_stream();
  96. if self.value.is_some() {
  97. self
  98. .ast_result
  99. .error_spanned_by(tokens, format!("duplicate attribute `{}`", self.name));
  100. } else {
  101. self.tokens = tokens;
  102. self.value = Some(value);
  103. }
  104. }
  105. fn set_opt<A: ToTokens>(&mut self, obj: A, value: Option<T>) {
  106. if let Some(value) = value {
  107. self.set(obj, value);
  108. }
  109. }
  110. pub(crate) fn set_if_none(&mut self, value: T) {
  111. if self.value.is_none() {
  112. self.value = Some(value);
  113. }
  114. }
  115. pub(crate) fn get(self) -> Option<T> {
  116. self.value
  117. }
  118. #[allow(dead_code)]
  119. fn get_with_tokens(self) -> Option<(TokenStream, T)> {
  120. match self.value {
  121. Some(v) => Some((self.tokens, v)),
  122. None => None,
  123. }
  124. }
  125. }
  126. pub struct PBStructAttrs {
  127. #[allow(dead_code)]
  128. name: String,
  129. pb_index: Option<syn::LitInt>,
  130. pb_one_of: bool,
  131. skip_pb_serializing: bool,
  132. skip_pb_deserializing: bool,
  133. serialize_pb_with: Option<syn::ExprPath>,
  134. deserialize_pb_with: Option<syn::ExprPath>,
  135. }
  136. pub fn is_recognizable_field(field: &syn::Field) -> bool {
  137. field
  138. .attrs
  139. .iter()
  140. .any(|attr| is_recognizable_attribute(attr))
  141. }
  142. impl PBStructAttrs {
  143. /// Extract out the `#[pb(...)]` attributes from a struct field.
  144. pub fn from_ast(ast_result: &ASTResult, index: usize, field: &syn::Field) -> Self {
  145. let mut pb_index = ASTAttr::none(ast_result, PB_INDEX);
  146. let mut pb_one_of = BoolAttr::none(ast_result, PB_ONE_OF);
  147. let mut serialize_pb_with = ASTAttr::none(ast_result, SERIALIZE_PB_WITH);
  148. let mut skip_pb_serializing = BoolAttr::none(ast_result, SKIP_PB_SERIALIZING);
  149. let mut deserialize_pb_with = ASTAttr::none(ast_result, DESERIALIZE_PB_WITH);
  150. let mut skip_pb_deserializing = BoolAttr::none(ast_result, SKIP_PB_DESERIALIZING);
  151. let ident = match &field.ident {
  152. Some(ident) => ident.to_string(),
  153. None => index.to_string(),
  154. };
  155. for meta_item in field
  156. .attrs
  157. .iter()
  158. .flat_map(|attr| get_pb_meta_items(ast_result, attr))
  159. .flatten()
  160. {
  161. match &meta_item {
  162. // Parse `#[pb(skip)]`
  163. Meta(Path(word)) if word == SKIP => {
  164. skip_pb_serializing.set_true(word);
  165. skip_pb_deserializing.set_true(word);
  166. },
  167. // Parse '#[pb(index = x)]'
  168. Meta(NameValue(m)) if m.path == PB_INDEX => {
  169. if let syn::Lit::Int(lit) = &m.lit {
  170. pb_index.set(&m.path, lit.clone());
  171. }
  172. },
  173. // Parse `#[pb(one_of)]`
  174. Meta(Path(path)) if path == PB_ONE_OF => {
  175. pb_one_of.set_true(path);
  176. },
  177. // Parse `#[pb(serialize_pb_with = "...")]`
  178. Meta(NameValue(m)) if m.path == SERIALIZE_PB_WITH => {
  179. if let Ok(path) = parse_lit_into_expr_path(ast_result, SERIALIZE_PB_WITH, &m.lit) {
  180. serialize_pb_with.set(&m.path, path);
  181. }
  182. },
  183. // Parse `#[pb(deserialize_pb_with = "...")]`
  184. Meta(NameValue(m)) if m.path == DESERIALIZE_PB_WITH => {
  185. if let Ok(path) = parse_lit_into_expr_path(ast_result, DESERIALIZE_PB_WITH, &m.lit) {
  186. deserialize_pb_with.set(&m.path, path);
  187. }
  188. },
  189. Meta(meta_item) => {
  190. let path = meta_item
  191. .path()
  192. .into_token_stream()
  193. .to_string()
  194. .replace(' ', "");
  195. ast_result.error_spanned_by(
  196. meta_item.path(),
  197. format!("unknown pb field attribute `{}`", path),
  198. );
  199. },
  200. Lit(lit) => {
  201. ast_result.error_spanned_by(lit, "unexpected literal in field attribute");
  202. },
  203. }
  204. }
  205. PBStructAttrs {
  206. name: ident,
  207. pb_index: pb_index.get(),
  208. pb_one_of: pb_one_of.get(),
  209. skip_pb_serializing: skip_pb_serializing.get(),
  210. skip_pb_deserializing: skip_pb_deserializing.get(),
  211. serialize_pb_with: serialize_pb_with.get(),
  212. deserialize_pb_with: deserialize_pb_with.get(),
  213. }
  214. }
  215. #[allow(dead_code)]
  216. pub fn pb_index(&self) -> Option<String> {
  217. self
  218. .pb_index
  219. .as_ref()
  220. .map(|lit| lit.base10_digits().to_string())
  221. }
  222. pub fn is_one_of(&self) -> bool {
  223. self.pb_one_of
  224. }
  225. pub fn serialize_pb_with(&self) -> Option<&syn::ExprPath> {
  226. self.serialize_pb_with.as_ref()
  227. }
  228. pub fn deserialize_pb_with(&self) -> Option<&syn::ExprPath> {
  229. self.deserialize_pb_with.as_ref()
  230. }
  231. pub fn skip_pb_serializing(&self) -> bool {
  232. self.skip_pb_serializing
  233. }
  234. pub fn skip_pb_deserializing(&self) -> bool {
  235. self.skip_pb_deserializing
  236. }
  237. }
  238. pub enum Default {
  239. /// Field must always be specified because it does not have a default.
  240. None,
  241. /// The default is given by `std::default::Default::default()`.
  242. Default,
  243. /// The default is given by this function.
  244. Path(syn::ExprPath),
  245. }
  246. pub fn is_recognizable_attribute(attr: &syn::Attribute) -> bool {
  247. attr.path == PB_ATTRS || attr.path == EVENT || attr.path == NODE_ATTRS || attr.path == NODES_ATTRS
  248. }
  249. pub fn get_pb_meta_items(
  250. cx: &ASTResult,
  251. attr: &syn::Attribute,
  252. ) -> Result<Vec<syn::NestedMeta>, ()> {
  253. // Only handle the attribute that we have defined
  254. if attr.path != PB_ATTRS {
  255. return Ok(vec![]);
  256. }
  257. // http://strymon.systems.ethz.ch/typename/syn/enum.Meta.html
  258. match attr.parse_meta() {
  259. Ok(List(meta)) => Ok(meta.nested.into_iter().collect()),
  260. Ok(other) => {
  261. cx.error_spanned_by(other, "expected #[pb(...)]");
  262. Err(())
  263. },
  264. Err(err) => {
  265. cx.error_spanned_by(attr, "attribute must be str, e.g. #[pb(xx = \"xxx\")]");
  266. cx.syn_error(err);
  267. Err(())
  268. },
  269. }
  270. }
  271. pub fn get_node_meta_items(
  272. cx: &ASTResult,
  273. attr: &syn::Attribute,
  274. ) -> Result<Vec<syn::NestedMeta>, ()> {
  275. // Only handle the attribute that we have defined
  276. if attr.path != NODE_ATTRS && attr.path != NODES_ATTRS {
  277. return Ok(vec![]);
  278. }
  279. // http://strymon.systems.ethz.ch/typename/syn/enum.Meta.html
  280. match attr.parse_meta() {
  281. Ok(List(meta)) => Ok(meta.nested.into_iter().collect()),
  282. Ok(_) => Ok(vec![]),
  283. Err(err) => {
  284. cx.error_spanned_by(attr, "attribute must be str, e.g. #[node(xx = \"xxx\")]");
  285. cx.syn_error(err);
  286. Err(())
  287. },
  288. }
  289. }
  290. pub fn get_event_meta_items(
  291. cx: &ASTResult,
  292. attr: &syn::Attribute,
  293. ) -> Result<Vec<syn::NestedMeta>, ()> {
  294. // Only handle the attribute that we have defined
  295. if attr.path != EVENT {
  296. return Ok(vec![]);
  297. }
  298. // http://strymon.systems.ethz.ch/typename/syn/enum.Meta.html
  299. match attr.parse_meta() {
  300. Ok(List(meta)) => Ok(meta.nested.into_iter().collect()),
  301. Ok(other) => {
  302. cx.error_spanned_by(other, "expected #[event(...)]");
  303. Err(())
  304. },
  305. Err(err) => {
  306. cx.error_spanned_by(attr, "attribute must be str, e.g. #[event(xx = \"xxx\")]");
  307. cx.syn_error(err);
  308. Err(())
  309. },
  310. }
  311. }
  312. pub fn parse_lit_into_expr_path(
  313. ast_result: &ASTResult,
  314. attr_name: Symbol,
  315. lit: &syn::Lit,
  316. ) -> Result<syn::ExprPath, ()> {
  317. let string = get_lit_str(ast_result, attr_name, lit)?;
  318. parse_lit_str(string).map_err(|_| {
  319. ast_result.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value()))
  320. })
  321. }
  322. fn get_lit_str<'a>(
  323. ast_result: &ASTResult,
  324. attr_name: Symbol,
  325. lit: &'a syn::Lit,
  326. ) -> Result<&'a syn::LitStr, ()> {
  327. if let syn::Lit::Str(lit) = lit {
  328. Ok(lit)
  329. } else {
  330. ast_result.error_spanned_by(
  331. lit,
  332. format!(
  333. "expected pb {} attribute to be a string: `{} = \"...\"`",
  334. attr_name, attr_name
  335. ),
  336. );
  337. Err(())
  338. }
  339. }
  340. fn parse_lit_into_ty(
  341. ast_result: &ASTResult,
  342. attr_name: Symbol,
  343. lit: &syn::Lit,
  344. ) -> Result<syn::Type, ()> {
  345. let string = get_lit_str(ast_result, attr_name, lit)?;
  346. parse_lit_str(string).map_err(|_| {
  347. ast_result.error_spanned_by(
  348. lit,
  349. format!("failed to parse type: {} = {:?}", attr_name, string.value()),
  350. )
  351. })
  352. }
  353. pub fn parse_lit_str<T>(s: &syn::LitStr) -> parse::Result<T>
  354. where
  355. T: Parse,
  356. {
  357. let tokens = spanned_tokens(s)?;
  358. syn::parse2(tokens)
  359. }
  360. fn spanned_tokens(s: &syn::LitStr) -> parse::Result<TokenStream> {
  361. let stream = syn::parse_str(&s.value())?;
  362. Ok(respan_token_stream(stream, s.span()))
  363. }
  364. fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
  365. stream
  366. .into_iter()
  367. .map(|token| respan_token_tree(token, span))
  368. .collect()
  369. }
  370. fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
  371. if let TokenTree::Group(g) = &mut token {
  372. *g = Group::new(g.delimiter(), respan_token_stream(g.stream(), span));
  373. }
  374. token.set_span(span);
  375. token
  376. }
  377. fn default_pb_type(ast_result: &ASTResult, ident: &syn::Ident) -> syn::Type {
  378. let take_ident = ident.to_string();
  379. let lit_str = syn::LitStr::new(&take_ident, ident.span());
  380. if let Ok(tokens) = spanned_tokens(&lit_str) {
  381. if let Ok(pb_struct_ty) = syn::parse2(tokens) {
  382. return pb_struct_ty;
  383. }
  384. }
  385. ast_result.error_spanned_by(
  386. ident,
  387. format!("❌ Can't find {} protobuf struct", take_ident),
  388. );
  389. panic!()
  390. }
  391. #[allow(dead_code)]
  392. pub fn is_option(ty: &syn::Type) -> bool {
  393. let path = match ungroup(ty) {
  394. syn::Type::Path(ty) => &ty.path,
  395. _ => {
  396. return false;
  397. },
  398. };
  399. let seg = match path.segments.last() {
  400. Some(seg) => seg,
  401. None => {
  402. return false;
  403. },
  404. };
  405. let args = match &seg.arguments {
  406. syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args,
  407. _ => {
  408. return false;
  409. },
  410. };
  411. seg.ident == "Option" && args.len() == 1
  412. }
  413. #[allow(dead_code)]
  414. pub fn ungroup(mut ty: &syn::Type) -> &syn::Type {
  415. while let syn::Type::Group(group) = ty {
  416. ty = &group.elem;
  417. }
  418. ty
  419. }
  420. struct BoolAttr<'c>(ASTAttr<'c, ()>);
  421. impl<'c> BoolAttr<'c> {
  422. fn none(ast_result: &'c ASTResult, name: Symbol) -> Self {
  423. BoolAttr(ASTAttr::none(ast_result, name))
  424. }
  425. fn set_true<A: ToTokens>(&mut self, obj: A) {
  426. self.0.set(obj, ());
  427. }
  428. fn get(&self) -> bool {
  429. self.0.value.is_some()
  430. }
  431. }