1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//! `#[derive(PyEnum)]` procedural macro.
//!
//! Parsing, validation, and codegen live in the submodules and are wired
//! together by [`derive_pyenum`]. The generated code only names items
//! re-exported from `pyenum::__private`, so the output is stable across
//! internal refactors of the runtime crate.
//!
//! See the [`pyenum`](https://docs.rs/pyenum) crate docs for usage,
//! worked examples, and scope.
use TokenStream;
/// Derive a [`pyenum::PyEnum`](../pyenum/trait.PyEnumTrait.html)
/// implementation for a unit-variant Rust enum.
///
/// The derive also emits PyO3 0.28 `IntoPyObject<'py>` (for `T` and `&T`)
/// and `FromPyObject<'a, 'py>` impls, so the Rust enum can appear directly
/// in `#[pyfunction]`, `#[pymethods]`, and `#[pyclass]` field signatures.
///
/// # Attributes
///
/// Enum-level (all optional):
///
/// * `#[pyenum(base = "Enum" | "IntEnum" | "StrEnum" | "Flag" | "IntFlag")]`
/// — select the Python base class. Defaults to `"Enum"`.
/// * `#[pyenum(name = "...")]` — override the Python class name. Defaults
/// to the Rust enum identifier.
///
/// Variant-level (optional, mutually exclusive with a Rust discriminant):
///
/// * `#[pyenum(value = "...")]` — explicit Python string value. Valid on
/// `StrEnum` (and `Enum`). Without it, `StrEnum` variants default to
/// Python's `auto()` semantics, which lowercase the variant name.
///
/// # Example
///
/// ```rust,ignore
/// use pyenum::{PyEnum, PyModuleExt};
/// use pyo3::prelude::*;
///
/// #[derive(Clone, Copy, PyEnum)]
/// #[pyenum(base = "IntEnum")]
/// pub enum HttpStatus {
/// Ok = 200,
/// NotFound = 404,
/// }
///
/// #[pyfunction]
/// fn classify(s: HttpStatus) -> HttpStatus { s }
///
/// #[pymodule]
/// fn demo(m: &Bound<'_, PyModule>) -> PyResult<()> {
/// m.add_enum::<HttpStatus>()?;
/// m.add_function(wrap_pyfunction!(classify, m)?)
/// }
/// ```
///
/// # Rejected at compile time
///
/// The macro emits spanned `compile_error!` diagnostics for:
///
/// * Tuple / struct variants, generics, lifetimes, and empty enums.
/// * Variant names colliding with Python keywords, dunders, or
/// `enum.Enum`-reserved attributes.
/// * Base/value shape mismatches (e.g. `#[pyenum(value = "x")]` on
/// `IntEnum`, or an integer discriminant on `StrEnum`).
/// * Duplicate resolved values — includes the `auto()` vs. explicit
/// collision on every integer-shaped base (`enum { A, B = 1 }` with
/// base `IntEnum`, `enum { Read, Write = 1 }` with base `Flag`, etc.)
/// and auto-lowercased name collisions on `StrEnum` (`Hello` + `HELLO`).
/// * Duplicate or unknown `#[pyenum(...)]` keys.