attr.rs 16 KB

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