Adds first-class Rust-backed Mizan to sit alongside mizan-django and
mizan-fastapi. A Rust dev writes:
#[derive(Mizan, Serialize, Deserialize)]
pub struct ProfileOutput { pub user_id: i64, pub name: String }
#[mizan::context("user")]
pub struct UserCtx;
#[mizan::client(context = UserCtx)]
pub async fn user_profile(_req: &RequestHandle<'_>, user_id: i64) -> ProfileOutput { ... }
…and gets byte-identical KDL to the Python emitters, served over the
same wire protocol the React / Rust / Vue / Svelte kernels speak.
New crates:
- cores/mizan-rust/ (Cargo: mizan-core) — IR types, KDL emitter, traits, registry,
runtime (compute_invalidation / compute_merges
ported from mizan-fastapi), graph_check with
structural type-matching
- cores/mizan-rust-macros/ (Cargo: mizan-macros) — #[derive(Mizan)], #[mizan::context],
#[mizan::client] proc macros
- backends/mizan-rust-axum/ (Cargo: mizan-axum) — axum HTTP adapter: /session/, /call/, /ctx/:name/
- tests/afi/rust_app/ — AFI fixture port + server / export-ir binaries
Substrate-shape moves required by cross-language equivalence:
- IR canonicalization: functions / contexts / context-members / shared-by
now sort alphabetically in both Python and Rust emitters. The IR is a
contract; linkme doesn't preserve declaration order, so canonical sort
is the only stable mapping. afi_ir.kdl + per-target baselines regenerated.
- MizanType::TYPE_NAME is a const (with a default type_name() reader) so
it's usable in linkme TypeEntry static initializers.
- Tree-shaken type registry: #[derive(Mizan)] only emits the trait impl;
the #[mizan::client] macro registers canonical-named entries from
fn signatures, including Vec<T> element types for ref resolution.
- Merge resolution is structural (NamedType shape comparison) rather than
by name — matches the Python types_match_for_merge semantics.
Three-way forcing functions:
- tests/afi/test_codegen_parity.py — Django ≡ FastAPI ≡ Rust on KDL bytes (3 pass)
- tests/rust/run_wire_parity.py — 12/12 probes against FastAPI + Rust (EXIT=0)
Incidental fixes surfaced by the new tests:
- Stale `from .registry import validate_registry` import removed from
mizan-django/setup/discovery.py (referenced a function that no longer
exists; was masking codegen-parity).
- BASE_DIR added to tests/afi/django_app/project/settings.py.
- /session/ endpoint added to mizan-fastapi for protocol-shaped readiness
probe parity (wire-parity harness now polls /api/mizan/session/ on both
backends rather than FastAPI's /openapi.json).
- Root .gitignore picks up Rust target/ across the tree so new crates
don't need per-crate gitignore.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
58 lines
2.1 KiB
Rust
58 lines
2.1 KiB
Rust
//! Mizan server-side IR substrate. Rust analog of `cores/mizan-python/src/mizan_core/`.
|
|
//!
|
|
//! Three load-bearing concerns:
|
|
//!
|
|
//! 1. **IR data model + KDL emitter.** `build_ir()` produces byte-equivalent
|
|
//! KDL to the Python emitter. Both backends emit the same contract.
|
|
//! 2. **Compile-time registry.** Proc macros from `mizan-macros` populate
|
|
//! linkme distributed slices (`TYPES`, `CONTEXTS`, `FUNCTIONS`) at the
|
|
//! consumer crate's expansion sites.
|
|
//! 3. **Runtime helpers.** `compute_invalidation` / `compute_merges` /
|
|
//! `lookup_function` ported from `mizan-fastapi`'s executor; the HTTP
|
|
//! adapter calls these per request.
|
|
//!
|
|
//! Consumers `use mizan_core::prelude::*;` and alias the crate as `mizan` at
|
|
//! their call sites so authored code reads `#[mizan::context]` / `#[mizan(...)]`.
|
|
|
|
pub mod graph_check;
|
|
pub mod ir;
|
|
pub mod kdl;
|
|
pub mod registry;
|
|
pub mod runtime;
|
|
pub mod traits;
|
|
|
|
pub use ir::{
|
|
AffectTarget, DefaultValue, NamedType, Primitive, StructField, Transport, TypeShape,
|
|
};
|
|
pub use kdl::{build_ir, snake_to_camel};
|
|
pub use registry::{
|
|
context_members, lookup_context, lookup_function, ContextEntry, TypeEntry, CONTEXTS,
|
|
FUNCTIONS, TYPES,
|
|
};
|
|
pub use runtime::{
|
|
compute_invalidation, compute_merges, InvalidationTarget, MergeEntry, MizanError,
|
|
RequestHandle,
|
|
};
|
|
pub use traits::{ContextMarker, FunctionSpec, InputParam, MizanType};
|
|
|
|
// Re-export proc macros so consumers depend on one crate.
|
|
pub use mizan_macros::{client, context, Mizan};
|
|
|
|
pub mod prelude {
|
|
pub use crate::ir::{
|
|
AffectTarget, DefaultValue, NamedType, Primitive, StructField, Transport, TypeShape,
|
|
};
|
|
pub use crate::registry::{ContextEntry, TypeEntry};
|
|
pub use crate::runtime::{MizanError, RequestHandle};
|
|
pub use crate::traits::{ContextMarker, FunctionSpec, InputParam, MizanType};
|
|
pub use mizan_macros::Mizan;
|
|
}
|
|
|
|
/// Internal re-exports used by `mizan-macros`-generated code. Not part of
|
|
/// the public API — consumers must not depend on names under `__priv`.
|
|
#[doc(hidden)]
|
|
pub mod __priv {
|
|
pub use linkme;
|
|
pub use serde_json;
|
|
}
|