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