nx_catalog_id_lookup.nx source
↩ module page · 290 lines · 15695 B
1// nx_catalog_id_lookup.nx -- string-id <-> sealed-enum bridge.
2//
3// CAPABILITY_COMPLETENESS: FULL (for shipped catalog enums;
4// new catalog entries register via the lookup-table extension
5// pattern documented inline)
6//
7// Phase 1.5 of NISHI_NSFW_LESSONS_AND_ADDITIVE_CATALOG.md:
8// bridges the JSONL catalog files (nxc2/seed/modesty_profiles.jsonl
9// + nxc2/seed/object_specs.jsonl) -- where each row's `id` field
10// is a human-readable string -- with the runtime sealed-enum
11// integers that nx_modesty_profile + nx_object_spec use.
12//
13// Without this bridge, every JSONL-loader would need to embed
14// the same string -> enum mapping. With it, ONE place owns the
15// canonical mapping; Phase 2 loaders compose against it.
16//
17// The lookup is OPEN-FORM lookup (no fancy hash table) because
18// the catalogs are small (16 modesty + 23 object specs). When
19// the catalog grows past a few hundred entries, swap to FNV-1a
20// hash table; the API stays.
21//
22// genealogy_id: substrate_additive_catalog_phase_1_5_2026_05_16
23// lineage_id: nx_catalog_id_lookup_v1
24
25import "nx_syscalls.nx"
26import "nx_runtime.nx"
27import "nx_tier.nx"
28import "nx_modesty_profile.nx"
29import "nx_object_spec.nx"
30
31// ===== string comparison helper ==================================
32//
33// Substrate doesn't have nx_str_eq imported here; build a focused
34// byte-by-byte comparator. Returns 1 if equal, 0 otherwise.
35
36func _idlk_streq(a: *u8, n: nx_int, lit: *u8) -> nx_int {
37 var i: nx_int = 0
38 while i < n {
39 let ac: nx_int = (a[i] as nx_int) & 255
40 let bc: nx_int = (lit[i] as nx_int) & 255
41 if ac != bc { return 0 }
42 if bc == 0 { return 0 }
43 i = i + 1
44 }
45 // Verify lit ends here (no trailing chars after our length).
46 if (lit[n] as nx_int) & 255 != 0 { return 0 }
47 return 1
48}
49
50// ===== modesty id -> enum ========================================
51//
52// Returns the NX_MODESTY_* sealed-enum integer for the given
53// canonical id string. Returns -1 if unknown.
54
55func nx_modesty_id_to_enum(id_buf: *u8, id_len: nx_int) -> nx_int {
56 if id_len <= 0 { return -1 }
57 if _idlk_streq(id_buf, id_len, "modern_western_casual" as *u8) == 1 {
58 return NX_MODESTY_MODERN_WESTERN_CASUAL
59 }
60 if _idlk_streq(id_buf, id_len, "modern_western_formal" as *u8) == 1 {
61 return NX_MODESTY_MODERN_WESTERN_FORMAL
62 }
63 if _idlk_streq(id_buf, id_len, "modern_western_beach" as *u8) == 1 {
64 return NX_MODESTY_MODERN_WESTERN_BEACH
65 }
66 if _idlk_streq(id_buf, id_len, "modern_lingerie" as *u8) == 1 {
67 return NX_MODESTY_MODERN_LINGERIE
68 }
69 if _idlk_streq(id_buf, id_len, "victorian" as *u8) == 1 {
70 return NX_MODESTY_VICTORIAN
71 }
72 if _idlk_streq(id_buf, id_len, "ancient_greek_athletic_m" as *u8) == 1 {
73 return NX_MODESTY_ANCIENT_GREEK_ATHLETIC_M
74 }
75 if _idlk_streq(id_buf, id_len, "ancient_greek_athletic_f" as *u8) == 1 {
76 return NX_MODESTY_ANCIENT_GREEK_ATHLETIC_F
77 }
78 if _idlk_streq(id_buf, id_len, "ancient_roman_public" as *u8) == 1 {
79 return NX_MODESTY_ANCIENT_ROMAN_PUBLIC
80 }
81 if _idlk_streq(id_buf, id_len, "renaissance_nobility" as *u8) == 1 {
82 return NX_MODESTY_RENAISSANCE_NOBILITY
83 }
84 if _idlk_streq(id_buf, id_len, "heian_court" as *u8) == 1 {
85 return NX_MODESTY_HEIAN_COURT
86 }
87 if _idlk_streq(id_buf, id_len, "islamic_hijab" as *u8) == 1 {
88 return NX_MODESTY_ISLAMIC_HIJAB
89 }
90 if _idlk_streq(id_buf, id_len, "islamic_niqab" as *u8) == 1 {
91 return NX_MODESTY_ISLAMIC_NIQAB
92 }
93 if _idlk_streq(id_buf, id_len, "hindu_sari" as *u8) == 1 {
94 return NX_MODESTY_HINDU_SARI
95 }
96 if _idlk_streq(id_buf, id_len, "medical_professional" as *u8) == 1 {
97 return NX_MODESTY_MEDICAL_PROFESSIONAL
98 }
99 if _idlk_streq(id_buf, id_len, "artistic_nude_renaissance" as *u8) == 1 {
100 return NX_MODESTY_ARTISTIC_NUDE_RENAISSANCE
101 }
102 if _idlk_streq(id_buf, id_len, "athletic_dance" as *u8) == 1 {
103 return NX_MODESTY_ATHLETIC_DANCE
104 }
105 return -1
106}
107
108// ===== modesty enum -> id ========================================
109//
110// Reverse lookup for human-readable phrase rendering.
111
112func nx_modesty_enum_to_id(profile_id: nx_int) -> *u8 {
113 if profile_id == NX_MODESTY_MODERN_WESTERN_CASUAL { return "modern_western_casual" as *u8 }
114 if profile_id == NX_MODESTY_MODERN_WESTERN_FORMAL { return "modern_western_formal" as *u8 }
115 if profile_id == NX_MODESTY_MODERN_WESTERN_BEACH { return "modern_western_beach" as *u8 }
116 if profile_id == NX_MODESTY_MODERN_LINGERIE { return "modern_lingerie" as *u8 }
117 if profile_id == NX_MODESTY_VICTORIAN { return "victorian" as *u8 }
118 if profile_id == NX_MODESTY_ANCIENT_GREEK_ATHLETIC_M { return "ancient_greek_athletic_m" as *u8 }
119 if profile_id == NX_MODESTY_ANCIENT_GREEK_ATHLETIC_F { return "ancient_greek_athletic_f" as *u8 }
120 if profile_id == NX_MODESTY_ANCIENT_ROMAN_PUBLIC { return "ancient_roman_public" as *u8 }
121 if profile_id == NX_MODESTY_RENAISSANCE_NOBILITY { return "renaissance_nobility" as *u8 }
122 if profile_id == NX_MODESTY_HEIAN_COURT { return "heian_court" as *u8 }
123 if profile_id == NX_MODESTY_ISLAMIC_HIJAB { return "islamic_hijab" as *u8 }
124 if profile_id == NX_MODESTY_ISLAMIC_NIQAB { return "islamic_niqab" as *u8 }
125 if profile_id == NX_MODESTY_HINDU_SARI { return "hindu_sari" as *u8 }
126 if profile_id == NX_MODESTY_MEDICAL_PROFESSIONAL { return "medical_professional" as *u8 }
127 if profile_id == NX_MODESTY_ARTISTIC_NUDE_RENAISSANCE { return "artistic_nude_renaissance" as *u8 }
128 if profile_id == NX_MODESTY_ATHLETIC_DANCE { return "athletic_dance" as *u8 }
129 return "unknown_profile" as *u8
130}
131
132// ===== object spec id -> enum ====================================
133
134func nx_object_spec_id_to_enum(id_buf: *u8, id_len: nx_int) -> nx_int {
135 if id_len <= 0 { return -1 }
136 if _idlk_streq(id_buf, id_len, "sword_long" as *u8) == 1 { return NX_SPEC_SWORD_LONG }
137 if _idlk_streq(id_buf, id_len, "sword_short" as *u8) == 1 { return NX_SPEC_SWORD_SHORT }
138 if _idlk_streq(id_buf, id_len, "dagger" as *u8) == 1 { return NX_SPEC_DAGGER }
139 if _idlk_streq(id_buf, id_len, "spear" as *u8) == 1 { return NX_SPEC_SPEAR }
140 if _idlk_streq(id_buf, id_len, "axe_battle" as *u8) == 1 { return NX_SPEC_AXE_BATTLE }
141 if _idlk_streq(id_buf, id_len, "mace" as *u8) == 1 { return NX_SPEC_MACE }
142 if _idlk_streq(id_buf, id_len, "hammer_war" as *u8) == 1 { return NX_SPEC_HAMMER_WAR }
143 if _idlk_streq(id_buf, id_len, "bow_long" as *u8) == 1 { return NX_SPEC_BOW_LONG }
144 if _idlk_streq(id_buf, id_len, "staff_quarter" as *u8) == 1 { return NX_SPEC_STAFF_QUARTER }
145 if _idlk_streq(id_buf, id_len, "wand_magic" as *u8) == 1 { return NX_SPEC_WAND_MAGIC }
146 if _idlk_streq(id_buf, id_len, "shirt_button" as *u8) == 1 { return NX_SPEC_SHIRT_BUTTON }
147 if _idlk_streq(id_buf, id_len, "shirt_t" as *u8) == 1 { return NX_SPEC_SHIRT_T }
148 if _idlk_streq(id_buf, id_len, "pants_jeans" as *u8) == 1 { return NX_SPEC_PANTS_JEANS }
149 if _idlk_streq(id_buf, id_len, "dress_sundress" as *u8) == 1 { return NX_SPEC_DRESS_SUNDRESS }
150 if _idlk_streq(id_buf, id_len, "coat_trench" as *u8) == 1 { return NX_SPEC_COAT_TRENCH }
151 if _idlk_streq(id_buf, id_len, "hat_fedora" as *u8) == 1 { return NX_SPEC_HAT_FEDORA }
152 if _idlk_streq(id_buf, id_len, "lingerie_bra" as *u8) == 1 { return NX_SPEC_LINGERIE_BRA }
153 if _idlk_streq(id_buf, id_len, "orc_standard" as *u8) == 1 { return NX_SPEC_ORC_STANDARD }
154 if _idlk_streq(id_buf, id_len, "elf_high" as *u8) == 1 { return NX_SPEC_ELF_HIGH }
155 if _idlk_streq(id_buf, id_len, "dragon_western" as *u8) == 1 { return NX_SPEC_DRAGON_WESTERN }
156 if _idlk_streq(id_buf, id_len, "werewolf" as *u8) == 1 { return NX_SPEC_WEREWOLF }
157 if _idlk_streq(id_buf, id_len, "car_sedan" as *u8) == 1 { return NX_SPEC_CAR_SEDAN }
158 if _idlk_streq(id_buf, id_len, "motorcycle" as *u8) == 1 { return NX_SPEC_MOTORCYCLE }
159 if _idlk_streq(id_buf, id_len, "castle_medieval" as *u8) == 1 { return NX_SPEC_CASTLE_MEDIEVAL }
160 if _idlk_streq(id_buf, id_len, "bubble_wand" as *u8) == 1 { return NX_SPEC_BUBBLE_WAND }
161 if _idlk_streq(id_buf, id_len, "pen_ballpoint" as *u8) == 1 { return NX_SPEC_PEN_BALLPOINT }
162 if _idlk_streq(id_buf, id_len, "torch" as *u8) == 1 { return NX_SPEC_TORCH }
163 if _idlk_streq(id_buf, id_len, "flashlight" as *u8) == 1 { return NX_SPEC_FLASHLIGHT }
164 return -1
165}
166
167// ===== part id (used in object_specs JSONL required_parts arrays) ==
168
169func nx_part_id_to_enum(name: *u8, len: nx_int) -> nx_int {
170 if len <= 0 { return -1 }
171 // Weapon parts
172 if _idlk_streq(name, len, "BLADE" as *u8) == 1 { return NX_PT_BLADE }
173 if _idlk_streq(name, len, "EDGE" as *u8) == 1 { return NX_PT_EDGE }
174 if _idlk_streq(name, len, "POINT" as *u8) == 1 { return NX_PT_POINT }
175 if _idlk_streq(name, len, "TANG" as *u8) == 1 { return NX_PT_TANG }
176 if _idlk_streq(name, len, "CROSSGUARD" as *u8) == 1 { return NX_PT_CROSSGUARD }
177 if _idlk_streq(name, len, "GRIP" as *u8) == 1 { return NX_PT_GRIP }
178 if _idlk_streq(name, len, "POMMEL" as *u8) == 1 { return NX_PT_POMMEL }
179 if _idlk_streq(name, len, "HAFT" as *u8) == 1 { return NX_PT_HAFT }
180 if _idlk_streq(name, len, "HEAD_WEAPON" as *u8) == 1 { return NX_PT_HEAD_WEAPON }
181 if _idlk_streq(name, len, "LIMB_BOW" as *u8) == 1 { return NX_PT_LIMB_BOW }
182 if _idlk_streq(name, len, "STRING_BOW" as *u8) == 1 { return NX_PT_STRING_BOW }
183 if _idlk_streq(name, len, "NOCK" as *u8) == 1 { return NX_PT_NOCK }
184 if _idlk_streq(name, len, "FLETCHING" as *u8) == 1 { return NX_PT_FLETCHING }
185 // Wand / non-weapon stick parts
186 if _idlk_streq(name, len, "HANDLE_STICK" as *u8) == 1 { return NX_PT_HANDLE_STICK }
187 if _idlk_streq(name, len, "LOOP" as *u8) == 1 { return NX_PT_LOOP }
188 if _idlk_streq(name, len, "FILM" as *u8) == 1 { return NX_PT_FILM }
189 if _idlk_streq(name, len, "NIB" as *u8) == 1 { return NX_PT_NIB }
190 if _idlk_streq(name, len, "TIP" as *u8) == 1 { return NX_PT_TIP }
191 if _idlk_streq(name, len, "FLAME" as *u8) == 1 { return NX_PT_FLAME }
192 // Clothing parts
193 if _idlk_streq(name, len, "COLLAR" as *u8) == 1 { return NX_PT_COLLAR }
194 if _idlk_streq(name, len, "NECKLINE" as *u8) == 1 { return NX_PT_NECKLINE }
195 if _idlk_streq(name, len, "SLEEVE_SHORT" as *u8) == 1 { return NX_PT_SLEEVE_SHORT }
196 if _idlk_streq(name, len, "SLEEVE_LONG" as *u8) == 1 { return NX_PT_SLEEVE_LONG }
197 if _idlk_streq(name, len, "CUFF" as *u8) == 1 { return NX_PT_CUFF }
198 if _idlk_streq(name, len, "HEM" as *u8) == 1 { return NX_PT_HEM }
199 if _idlk_streq(name, len, "WAISTBAND" as *u8) == 1 { return NX_PT_WAISTBAND }
200 if _idlk_streq(name, len, "BUTTON" as *u8) == 1 { return NX_PT_BUTTON }
201 if _idlk_streq(name, len, "ZIPPER" as *u8) == 1 { return NX_PT_ZIPPER }
202 if _idlk_streq(name, len, "POCKET" as *u8) == 1 { return NX_PT_POCKET }
203 if _idlk_streq(name, len, "LAPEL" as *u8) == 1 { return NX_PT_LAPEL }
204 if _idlk_streq(name, len, "HOOD" as *u8) == 1 { return NX_PT_HOOD }
205 if _idlk_streq(name, len, "BRA_CUP" as *u8) == 1 { return NX_PT_BRA_CUP }
206 if _idlk_streq(name, len, "BRA_STRAP" as *u8) == 1 { return NX_PT_BRA_STRAP }
207 // Creature parts
208 if _idlk_streq(name, len, "HEAD" as *u8) == 1 { return NX_PT_HEAD }
209 if _idlk_streq(name, len, "TUSK" as *u8) == 1 { return NX_PT_TUSK }
210 if _idlk_streq(name, len, "HORN" as *u8) == 1 { return NX_PT_HORN }
211 if _idlk_streq(name, len, "WING" as *u8) == 1 { return NX_PT_WING }
212 if _idlk_streq(name, len, "TAIL" as *u8) == 1 { return NX_PT_TAIL }
213 if _idlk_streq(name, len, "SCALE" as *u8) == 1 { return NX_PT_SCALE }
214 if _idlk_streq(name, len, "FUR" as *u8) == 1 { return NX_PT_FUR }
215 if _idlk_streq(name, len, "POINTED_EAR" as *u8) == 1 { return NX_PT_POINTED_EAR }
216 if _idlk_streq(name, len, "CLAW" as *u8) == 1 { return NX_PT_CLAW }
217 if _idlk_streq(name, len, "FANG" as *u8) == 1 { return NX_PT_FANG }
218 // Vehicle parts
219 if _idlk_streq(name, len, "WHEEL" as *u8) == 1 { return NX_PT_WHEEL }
220 if _idlk_streq(name, len, "WINDSHIELD" as *u8) == 1 { return NX_PT_WINDSHIELD }
221 if _idlk_streq(name, len, "HEADLIGHT" as *u8) == 1 { return NX_PT_HEADLIGHT }
222 if _idlk_streq(name, len, "LICENSE_PLATE" as *u8) == 1 { return NX_PT_LICENSE_PLATE }
223 if _idlk_streq(name, len, "MIRROR" as *u8) == 1 { return NX_PT_MIRROR }
224 if _idlk_streq(name, len, "GRILLE" as *u8) == 1 { return NX_PT_GRILLE }
225 if _idlk_streq(name, len, "HANDLEBAR" as *u8) == 1 { return NX_PT_HANDLEBAR }
226 // Architecture parts
227 if _idlk_streq(name, len, "WALL" as *u8) == 1 { return NX_PT_WALL }
228 if _idlk_streq(name, len, "WINDOW_PANE" as *u8) == 1 { return NX_PT_WINDOW_PANE }
229 if _idlk_streq(name, len, "DOOR" as *u8) == 1 { return NX_PT_DOOR }
230 if _idlk_streq(name, len, "ROOF" as *u8) == 1 { return NX_PT_ROOF }
231 if _idlk_streq(name, len, "BATTLEMENT" as *u8) == 1 { return NX_PT_BATTLEMENT }
232 if _idlk_streq(name, len, "ARROW_SLIT" as *u8) == 1 { return NX_PT_ARROW_SLIT }
233 if _idlk_streq(name, len, "TURRET" as *u8) == 1 { return NX_PT_TURRET }
234 if _idlk_streq(name, len, "CHIMNEY" as *u8) == 1 { return NX_PT_CHIMNEY }
235 return -1
236}
237
238// ===== self-test =================================================
239
240func main() -> nx_int {
241 // ---- modesty: forward lookups ----
242 let s1: *u8 = "modern_western_casual" as *u8
243 if nx_modesty_id_to_enum(s1, 21) != NX_MODESTY_MODERN_WESTERN_CASUAL { return 1 }
244 let s2: *u8 = "victorian" as *u8
245 if nx_modesty_id_to_enum(s2, 9) != NX_MODESTY_VICTORIAN { return 2 }
246 let s3: *u8 = "islamic_niqab" as *u8
247 if nx_modesty_id_to_enum(s3, 13) != NX_MODESTY_ISLAMIC_NIQAB { return 3 }
248 let s4: *u8 = "heian_court" as *u8
249 if nx_modesty_id_to_enum(s4, 11) != NX_MODESTY_HEIAN_COURT { return 4 }
250 let s5: *u8 = "hindu_sari" as *u8
251 if nx_modesty_id_to_enum(s5, 10) != NX_MODESTY_HINDU_SARI { return 5 }
252
253 // ---- modesty: unknown returns -1 ----
254 let s_bad: *u8 = "not_a_real_profile" as *u8
255 if nx_modesty_id_to_enum(s_bad, 18) != -1 { return 10 }
256
257 // ---- modesty: reverse lookup ----
258 let p_back: *u8 = nx_modesty_enum_to_id(NX_MODESTY_VICTORIAN)
259 if _idlk_streq(p_back, 9, "victorian" as *u8) != 1 { return 20 }
260 let p_unk: *u8 = nx_modesty_enum_to_id(NX_MODESTY_N_PROFILES)
261 if _idlk_streq(p_unk, 15, "unknown_profile" as *u8) != 1 { return 21 }
262
263 // ---- object spec: forward lookups ----
264 let o1: *u8 = "sword_long" as *u8
265 if nx_object_spec_id_to_enum(o1, 10) != NX_SPEC_SWORD_LONG { return 30 }
266 let o2: *u8 = "bubble_wand" as *u8
267 if nx_object_spec_id_to_enum(o2, 11) != NX_SPEC_BUBBLE_WAND { return 31 }
268 let o3: *u8 = "dragon_western" as *u8
269 if nx_object_spec_id_to_enum(o3, 14) != NX_SPEC_DRAGON_WESTERN { return 32 }
270 let o4: *u8 = "orc_standard" as *u8
271 if nx_object_spec_id_to_enum(o4, 12) != NX_SPEC_ORC_STANDARD { return 33 }
272
273 // ---- part id: forward lookups (the JSONL row's required_parts[] entries) ----
274 let pt1: *u8 = "BLADE" as *u8
275 if nx_part_id_to_enum(pt1, 5) != NX_PT_BLADE { return 40 }
276 let pt2: *u8 = "CROSSGUARD" as *u8
277 if nx_part_id_to_enum(pt2, 10) != NX_PT_CROSSGUARD { return 41 }
278 let pt3: *u8 = "LOOP" as *u8
279 if nx_part_id_to_enum(pt3, 4) != NX_PT_LOOP { return 42 }
280 let pt4: *u8 = "POINTED_EAR" as *u8
281 if nx_part_id_to_enum(pt4, 11) != NX_PT_POINTED_EAR { return 43 }
282 let pt5: *u8 = "BATTLEMENT" as *u8
283 if nx_part_id_to_enum(pt5, 10) != NX_PT_BATTLEMENT { return 44 }
284
285 // ---- part id: unknown ----
286 let pt_bad: *u8 = "NOT_A_PART" as *u8
287 if nx_part_id_to_enum(pt_bad, 10) != -1 { return 50 }
288
289 return 0
290}