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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! Boot-time `Sassi` registration via the `inventory` crate.
//!
//! `#[model]` (via `model::cacheable::expand` — when `Cacheable`
//! applies, i.e. `pk` ≠ `None`) emits one `inventory::submit!` per
//! model, each containing a `SassiBootHook` whose `fn(&mut Sassi)`
//! constructs a `Punnu<T>` and registers it on the orchestrator.
//!
//! `DjogiContext::from_pool` (and any other top-level constructor)
//! walks `inventory::iter::<SassiBootHook>()` once with a fresh
//! `&mut Sassi`, then freezes into `Arc<Sassi>` and stores it on the
//! context. After boot the registry is read-only.
//!
//! Cross-context behaviour: each top-level `DjogiContext` builds its
//! own `Sassi`. `begin()` / `atomic(&mut pool_ctx, ...)` SHARE the parent's
//! `Arc<Sassi>` (cache state is transaction-scope-agnostic). `atomic(&pool,
//! ...)` constructs a fresh top-level transaction context because no parent
//! context was supplied. This is the "DjogiContext IS the tenant boundary"
//! contract from cluster 8δ T7.4.
/// Link-time `Sassi` registration handle emitted by `#[model]`.
///
/// # What
///
/// Every `#[model]` struct (with the exception of `pk = None`) emits one
/// `inventory::submit!` of a `SassiBootHook` — a thin newtype around a
/// `fn(&mut Sassi)` registration pointer. At top-level
/// [`DjogiContext`](crate::DjogiContext) construction time
/// (`from_pool`, `from_connection`), the framework walks the inventory
/// once and applies every hook so the context's `Sassi` starts with a
/// `Punnu<T>` registered for each `Cacheable` model type compiled into
/// the binary.
///
/// # Why this is hidden from rustdoc
///
/// `SassiBootHook` is link-time machinery, not adopter-facing API.
/// Adopters should never name this type, read its inner field, or
/// construct an instance. The struct is `#[doc(hidden)]`, the inner
/// `fn` pointer is `pub(crate)`, and the
/// [`__djogi_from_model_macro`](Self::__djogi_from_model_macro)
/// constructor is `#[doc(hidden) pub]` solely so macro-emitted code in
/// downstream crates can call it through the
/// `::djogi::SassiBootHook::__djogi_from_model_macro` path (per
/// `feedback_macro_path_routing.md`). Narrowing the surface keeps the
/// framework free to evolve the inventory wiring (richer registration
/// shape, batched hooks per app, swap `inventory` for a different
/// link-time mechanism, etc.) without breaking the v0.1.0 adopter API.
///
/// # Adopter usage
///
/// Adopters interact with the framework's cache surface through the
/// `Sassi` registry built for them at context construction time —
/// never by naming `SassiBootHook` directly:
///
/// ```rust
/// use djogi::prelude::*;
///
/// // `pub struct` matches the macro-emitted `pub` visages (`PostPublic`,
/// // `PostSelfView`, `PostAdmin`, `PostExport`) carrying `type Model =
/// // Post` per the restored Phase 8.5 #231 `DjogiVisage::Model`
/// // associated-type contract. A `pub` visage referencing a private
/// // source model would trip rustc's `private_interfaces` / E0446
/// // check.
/// #[model(table = "posts")]
/// #[derive(Debug, Clone)]
/// pub struct Post {
/// pub title: String,
/// pub body: String,
/// }
///
/// fn typed_pool(ctx: &DjogiContext) {
/// // The boot hook for `Post` ran when `ctx` was constructed —
/// // `ctx.punnu::<Post>()` returns the registered `Arc<Punnu<Post>>`
/// // without the adopter ever naming `SassiBootHook`.
/// let _post_pool = ctx.punnu::<Post>();
/// }
/// ```
///
/// Macro-emitted code reaches this type through the
/// `::djogi::SassiBootHook` re-export at the crate root.
fn);
collect!;