blob: edb403da20fc697365d758650884dc2d339491d5 [file] [log] [blame]
David Tolnay7db73692019-10-20 14:51:12 -04001use crate::syntax::{Derive, Doc};
2use proc_macro2::Ident;
David Tolnayb129ea72020-05-10 14:29:30 -07003use syn::parse::{ParseStream, Parser as _};
David Tolnay7db73692019-10-20 14:51:12 -04004use syn::{Attribute, Error, LitStr, Path, Result, Token};
5
David Tolnayb129ea72020-05-10 14:29:30 -07006#[derive(Default)]
7pub struct Parser<'a> {
8 pub doc: Option<&'a mut Doc>,
9 pub derives: Option<&'a mut Vec<Derive>>,
10}
11
David Tolnay7db73692019-10-20 14:51:12 -040012pub(super) fn parse_doc(attrs: &[Attribute]) -> Result<Doc> {
13 let mut doc = Doc::new();
David Tolnayb129ea72020-05-10 14:29:30 -070014 parse(
15 attrs,
16 Parser {
17 doc: Some(&mut doc),
18 ..Parser::default()
19 },
20 )?;
David Tolnay7db73692019-10-20 14:51:12 -040021 Ok(doc)
22}
23
David Tolnayb129ea72020-05-10 14:29:30 -070024pub(super) fn parse(attrs: &[Attribute], mut parser: Parser) -> Result<()> {
David Tolnay7db73692019-10-20 14:51:12 -040025 for attr in attrs {
26 if attr.path.is_ident("doc") {
David Tolnayb129ea72020-05-10 14:29:30 -070027 if let Some(doc) = &mut parser.doc {
28 let lit = parse_doc_attribute.parse2(attr.tokens.clone())?;
29 doc.push(lit);
30 continue;
31 }
David Tolnay7db73692019-10-20 14:51:12 -040032 } else if attr.path.is_ident("derive") {
David Tolnayb129ea72020-05-10 14:29:30 -070033 if let Some(derives) = &mut parser.derives {
David Tolnay7db73692019-10-20 14:51:12 -040034 derives.extend(attr.parse_args_with(parse_derive_attribute)?);
35 continue;
36 }
37 }
38 return Err(Error::new_spanned(attr, "unsupported attribute"));
39 }
40 Ok(())
41}
42
43fn parse_doc_attribute(input: ParseStream) -> Result<LitStr> {
44 input.parse::<Token![=]>()?;
45 let lit: LitStr = input.parse()?;
46 Ok(lit)
47}
48
David Tolnaye86b9cf2020-05-10 14:24:29 -070049fn parse_derive_attribute(input: ParseStream) -> Result<Vec<Derive>> {
David Tolnay7db73692019-10-20 14:51:12 -040050 input
51 .parse_terminated::<Path, Token![,]>(Path::parse_mod_style)?
52 .into_iter()
David Tolnaye86b9cf2020-05-10 14:24:29 -070053 .map(|path| {
54 if let Some(ident) = path.get_ident() {
55 if let Some(derive) = Derive::from(ident) {
56 return Ok(derive);
57 }
58 }
59 Err(Error::new_spanned(path, "unsupported derive"))
David Tolnay7db73692019-10-20 14:51:12 -040060 })
61 .collect()
62}
63
64impl Derive {
65 pub fn from(ident: &Ident) -> Option<Self> {
66 match ident.to_string().as_str() {
67 "Clone" => Some(Derive::Clone),
68 "Copy" => Some(Derive::Copy),
69 _ => None,
70 }
71 }
72}
73
74impl AsRef<str> for Derive {
75 fn as_ref(&self) -> &str {
76 match self {
77 Derive::Clone => "Clone",
78 Derive::Copy => "Copy",
79 }
80 }
81}