nx_decl_base.nx source
↩ module page · 118 lines · 4249 B
1// nx_decl_base.nx -- shared base struct for the #tag declarator family.
2//
3// license_tier: ORIGINAL
4//
5// Object-oriented composition discipline: every `nx_decl_*` primitive
6// shares a HEADER struct (seed, modifier, is_valid) that's validated
7// + initialized centrally. Derived types compose by EMBEDDING (as the
8// first pointer field) and delegating the header validate to this
9// module.
10//
11// Today's `nx_decl_*` family duplicates the same validation 5 times
12// (random_environment, simple_scene, combat_arena, dungeon_floor,
13// townscape). This file centralizes that into ONE base. Migration
14// is additive: existing declarators keep their current shape; new
15// declarators can compose via `NxDeclBase` and `nx_decl_base_init`.
16//
17// Pattern (OO in substrate-procedural style):
18//
19// struct NxFooDecl {
20// base: *NxDeclBase, // pointer to shared header
21// foo_specific_a: nx_int,
22// foo_specific_b: nx_int,
23// }
24//
25// func nx_decl_foo(out: *NxFooDecl, modifier: nx_int, seed: nx_int) -> nx_int {
26// let base: *NxDeclBase = nx_decl_base_alloc()
27// let ok: nx_int = nx_decl_base_init(base, modifier, seed)
28// if ok == 0 { return 0 }
29// out.base = base
30// // ... fill foo-specific fields ...
31// return 1
32// }
33//
34// Then `out.base.is_valid`, `out.base.modifier`, `out.base.seed` are
35// uniform across the family. Inheritance discipline: substrate-
36// procedural has no method dispatch, but composition + a shared
37// init/validate is the practical equivalent.
38//
39// Per cardinals:
40// - DRY-through-shared-libraries: 5 copies of the same validate
41// collapse to one.
42// - Build-the-engine-not-instances: this IS the engine for the
43// #tag family.
44
45// nx_safety_envelope:
46// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
47// sil_target: SIL1
48// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
49// verdict: NOT_YET_EVALUATED
50
51import "nx_syscalls.nx"
52import "nx_types.nx"
53import "nx_tier.nx"
54const NX_MAGIC_2654435761: i64 = 2654435761
55const NX_MAGIC_374761393: i64 = 374761393
56
57// ---- The shared header struct -----------------------------------
58struct NxDeclBase {
59 seed: nx_int,
60 modifier: nx_int,
61 is_valid: nx_int,
62}
63
64// ---- The modifier enum (single source of truth) -----------------
65// Lifted from nx_decl_random_environment.nx so every declarator
66// references the SAME constants -- no per-file definitions.
67const NX_DECL_MOD_REAL: nx_int = 0
68const NX_DECL_MOD_FANTASY: nx_int = 1
69const NX_DECL_MOD_SCI_FI: nx_int = 2
70const NX_DECL_MOD_N: nx_int = 3
71
72func nx_decl_mod_is_valid(m: nx_int) -> nx_int {
73 if m < 0 { return 0 }
74 if m >= NX_DECL_MOD_N { return 0 }
75 return 1
76}
77
78// Elm-style reflection.
79func nx_decl_mod_name(m: nx_int) -> *u8 {
80 if m == NX_DECL_MOD_REAL { return "REAL" as *u8 }
81 if m == NX_DECL_MOD_FANTASY { return "FANTASY" as *u8 }
82 if m == NX_DECL_MOD_SCI_FI { return "SCI_FI" as *u8 }
83 return "<invalid modifier>" as *u8
84}
85
86// ---- Centralized init/validate ----------------------------------
87//
88// Returns 1 on success (base populated), 0 on invalid modifier (base
89// has is_valid=0 and is otherwise undefined). Caller checks the
90// return value OR base.is_valid -- they say the same thing.
91func nx_decl_base_init(base: *NxDeclBase, modifier: nx_int, seed: nx_int) -> nx_int {
92 if nx_decl_mod_is_valid(modifier) == 0 {
93 base.is_valid = 0
94 return 0
95 }
96 base.seed = seed
97 base.modifier = modifier
98 base.is_valid = 1
99 return 1
100}
101
102// Allocator for callers that prefer composition-by-pointer.
103func nx_decl_base_alloc() -> *NxDeclBase {
104 let raw: *u8 = sys_mmap(48)
105 let b: *NxDeclBase = raw as *NxDeclBase
106 return b
107}
108
109// ---- Shared seed-mixing helper (Knuth multiplicative hash mod N) -
110//
111// Every declarator uses this for deterministic per-field salting.
112// Single source of truth so future hash-algorithm swaps are one edit.
113func nx_decl_hash_mod(seed: nx_int, salt: nx_int, modulus: nx_int) -> nx_int {
114 let mixed: nx_int = seed * NX_MAGIC_2654435761 + salt * NX_MAGIC_374761393
115 var v: nx_int = mixed % modulus
116 if v < 0 { v = 0 - v }
117 return v
118}