Files
2026-07-30 21:12:29 -04:00

83 lines
2.3 KiB
Python

"""The typed shapes a Pydantic model lowers to before Rust is emitted.
`TypeShape` is deliberately isomorphic to Mizan's KDL `TypeShape`, so the
two can be converted without a lookup table.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional
class Primitive(str, Enum):
INTEGER = "integer"
NUMBER = "number"
BOOLEAN = "boolean"
STRING = "string"
@dataclass(frozen=True)
class TypeShape:
"""A recursive type shape. Exactly one variant field is set."""
primitive: Optional[Primitive] = None
int_width: Optional[int] = None
"""8 / 16 / 32 / 64, or None when unspecified. Only read alongside
`primitive == INTEGER`, and only by emitters that distinguish widths."""
int_signed: Optional[bool] = None
"""True for i8..i64, False for u8..u64, None when unspecified."""
float_width: Optional[int] = None
"""16 / 32 / 64, or None when unspecified. Only meaningful alongside
`primitive == NUMBER`."""
ref: Optional[str] = None
list_inner: Optional["TypeShape"] = None
optional_inner: Optional["TypeShape"] = None
enum_variants: Optional[tuple[str, ...]] = None
union_branches: Optional[tuple["TypeShape", ...]] = None
map_value: Optional["TypeShape"] = None
"""`dict[K, V]` value shape."""
map_key: Optional["TypeShape"] = None
"""Set only when the key is a NewType. Wire keys are always strings;
this keeps the typed identity on the Rust side."""
array_element: Optional["TypeShape"] = None
"""Fixed-length element: `tuple[T, T, T]` lowers to element T, length 3,
and emits `[T; 3]`."""
array_length: Optional[int] = None
@dataclass(frozen=True)
class DefaultValue:
"""A field default captured during introspection. `kind` discriminates
how the emitter renders `literal`."""
kind: str # integer | number | boolean | string | null | empty_seq |
# empty_map | tuple | enum_variant | compound_model | compound
literal: object
@dataclass(frozen=True)
class FieldDecl:
name: str
shape: TypeShape
required: bool
default: Optional[DefaultValue] = None
@dataclass(frozen=True)
class ModelDecl:
"""One Pydantic class, lowered field by field."""
name: str
fields: tuple[FieldDecl, ...] = field(default_factory=tuple)
docstring: Optional[str] = None