attr.rs 17 KB

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