pyenum_derive/lib.rs
1//! `#[derive(PyEnum)]` procedural macro.
2//!
3//! This is the entry-point crate. Parsing, validation, and codegen live in
4//! the submodules and are wired together by [`derive_pyenum`] below. The
5//! generated code references only items re-exported from `pyenum::__private`
6//! so the output is feature-flag-free — the runtime crate's `compat` module
7//! resolves those names per the active `pyo3-0_XX` feature.
8
9use proc_macro::TokenStream;
10
11mod codegen;
12mod parse;
13mod reserved;
14mod validate;
15
16/// Derive a `pyenum::PyEnum` implementation for a unit-variant Rust enum.
17///
18/// Enum-level attributes (all optional):
19///
20/// * `#[pyenum(base = "Enum" | "IntEnum" | "StrEnum" | "Flag" | "IntFlag")]`
21/// — select the Python base class. Defaults to `"Enum"`.
22/// * `#[pyenum(name = "...")]` — override the Python class name. Defaults
23/// to the Rust enum identifier.
24///
25/// Variant-level attributes (all optional, mutually exclusive with a Rust
26/// discriminant on the same variant):
27///
28/// * `#[pyenum(value = "...")]` — explicit Python string value. Only
29/// valid when the enum base is `StrEnum` or `Enum`. Without this
30/// attribute (and without a Rust discriminant), `StrEnum` variants
31/// default to Python's `auto()` semantics, which lowercase the variant
32/// name.
33#[proc_macro_derive(PyEnum, attributes(pyenum))]
34pub fn derive_pyenum(input: TokenStream) -> TokenStream {
35 let spec = match parse::parse_derive_input(input.into()) {
36 Ok(spec) => spec,
37 Err(err) => return err.to_compile_error().into(),
38 };
39 let spec = match validate::run(spec) {
40 Ok(spec) => spec,
41 Err(err) => return err.to_compile_error().into(),
42 };
43 codegen::emit(&spec).into()
44}