"""Rust identifier hygiene.""" from __future__ import annotations # Strict and reserved-for-future-use keywords from the Rust reference's # keyword table, 2021 edition. _RUST_KEYWORDS = frozenset({ "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", "self", "Self", "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where", "while", "async", "await", "dyn", "abstract", "become", "box", "do", "final", "macro", "override", "priv", "typeof", "unsized", "virtual", "yield", "try", "union", # contextual, but escaping it costs nothing }) def to_rust_ident(name: str) -> str: """`name`, or `r#name` when it collides with a keyword. Field casing is left alone — the caller owns that convention. """ if name in _RUST_KEYWORDS: return f"r#{name}" return name def to_rust_variant_ident(python_member_name: str) -> str: """`SONNET` -> `Sonnet`, `MY_OPTION` -> `MyOption`. Enum declarations and enum-valued defaults are emitted from different places and both call this; two implementations would disagree. """ return "".join(part.capitalize() for part in python_member_name.split("_") if part)