pyo3_macros_backend/
konst.rs

1use 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    /// Null-terminated Python name
29    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}
⚠️ Internal Docs ⚠️ Not Public API 👉 Official Docs Here