1use std::borrow::Cow;
2
3use crate::{
4 attributes::{self, get_pyo3_options, take_attributes, NameAttribute},
5 deprecations::Deprecations,
6};
7use proc_macro2::{Ident, TokenStream};
8use quote::quote;
9use syn::{
10 ext::IdentExt,
11 parse::{Parse, ParseStream},
12 spanned::Spanned,
13 Result,
14};
15
16pub struct ConstSpec {
17 pub rust_ident: syn::Ident,
18 pub attributes: ConstAttributes,
19}
20
21impl ConstSpec {
22 pub fn python_name(&self) -> Cow<'_, Ident> {
23 if let Some(name: &KeywordAttribute) = &self.attributes.name {
24 Cow::Borrowed(&name.value.0)
25 } else {
26 Cow::Owned(self.rust_ident.unraw())
27 }
28 }
29
30 /// Null-terminated Python name
31 pub fn null_terminated_python_name(&self) -> TokenStream {
32 let name: String = format!("{}\0", self.python_name());
33 quote!({#name})
34 }
35}
36
37pub struct ConstAttributes {
38 pub is_class_attr: bool,
39 pub name: Option<NameAttribute>,
40 pub deprecations: Deprecations,
41}
42
43pub enum PyO3ConstAttribute {
44 Name(NameAttribute),
45}
46
47impl Parse for PyO3ConstAttribute {
48 fn parse(input: ParseStream<'_>) -> Result<Self> {
49 let lookahead: Lookahead1<'_> = input.lookahead1();
50 if lookahead.peek(token:attributes::kw::name) {
51 input.parse().map(op:PyO3ConstAttribute::Name)
52 } else {
53 Err(lookahead.error())
54 }
55 }
56}
57
58impl ConstAttributes {
59 pub fn from_attrs(attrs: &mut Vec<syn::Attribute>) -> syn::Result<Self> {
60 let mut attributes = ConstAttributes {
61 is_class_attr: false,
62 name: None,
63 deprecations: Deprecations::new(),
64 };
65
66 take_attributes(attrs, |attr| {
67 if attr.path().is_ident("classattr") {
68 ensure_spanned!(
69 matches!(attr.meta, syn::Meta::Path(..)),
70 attr.span() => "`#[classattr]` does not take any arguments"
71 );
72 attributes.is_class_attr = true;
73 Ok(true)
74 } else if let Some(pyo3_attributes) = get_pyo3_options(attr)? {
75 for pyo3_attr in pyo3_attributes {
76 match pyo3_attr {
77 PyO3ConstAttribute::Name(name) => attributes.set_name(name)?,
78 }
79 }
80 Ok(true)
81 } else {
82 Ok(false)
83 }
84 })?;
85
86 Ok(attributes)
87 }
88
89 fn set_name(&mut self, name: NameAttribute) -> Result<()> {
90 ensure_spanned!(
91 self.name.is_none(),
92 name.span() => "`name` may only be specified once"
93 );
94 self.name = Some(name);
95 Ok(())
96 }
97}
98