code wiki / (root) / nx_bills_store.nx

nx_bills_store.nx source

↩ module page · 91 lines · 3824 B

1// nx_bills_store.nx -- per-respondent BILL STORE so the climb-out runs on the person's REAL recurring bills, 2// not representative ones. nx_bills is the pure engine (monthly/due-soon/overdue over arrays); this is the 3// sovereign persistence under it: each person's bills live as a content-addressed seg-store record keyed 4// "bills:<respondent>" (last-wins), a packed i64 buffer [count, then count*5 fields]. A bill = amount(cents), 5// cadence(months), due_day(1..31), category(BL_*), paid(0/1). Add is read-modify-write (idempotent-safe per 6// commit). No floats, no .tsv, no hardware writes -- pure sovereign storage feeding the existing engine. 7// license_tier: ORIGINAL 8import "nx_syscalls.nx" 9import "nx_seg_store.nx" 10import "nx_bills.nx" 11 12const BS_FIELDS: i64 = 5 // amount, cadence, due_day, category, paid 13const BS_MAX: i64 = 64 // cap on bills per person (a packed-record bound, DATA) 14 15// build "bills:<respondent>" into out (NUL-terminated); returns length. 16func bs_key(respondent: *u8, out: *u8) -> i64 { 17 var o: i64 = 0 18 let p: *u8 = "bills:\x00" as *u8 19 var i: i64 = 0 20 while p[i] != (0 as u8) { out[o] = p[i]; o = o + 1; i = i + 1 } 21 i = 0 22 while respondent[i] != (0 as u8) { out[o] = respondent[i]; o = o + 1; i = i + 1 } 23 out[o] = 0 as u8 24 return o 25} 26 27// load the raw packed record for a respondent into buf (aligned i64): buf[0]=count, then count*5 fields. 28// Copies bytes into the (page-aligned) buf so the i64 reads are aligned. Returns the count. 29func bs_load_raw(prefix: *u8, respondent: *u8, buf: *i64) -> i64 { 30 buf[0] = 0 31 let key: *u8 = sys_mmap(256) 32 bs_key(respondent, key) 33 let h: *i64 = ss_open(prefix) 34 if (h as i64) == 0 { return 0 } 35 let pp: *i64 = sys_mmap(16) as *i64 36 let ll: *i64 = sys_mmap(16) as *i64 37 if ss_hget(h, key, pp, ll) == 1 { 38 let src: *u8 = pp[0] as *u8 39 let nbytes: i64 = ll[0] 40 let bb: *u8 = buf as *u8 41 var i: i64 = 0 42 while i < nbytes { bb[i] = src[i]; i = i + 1 } 43 } 44 return buf[0] 45} 46 47// add one bill for a respondent (read-modify-write). returns 0 ok, <0 on cap/store error. 48func bs_add(prefix: *u8, respondent: *u8, amount: i64, cadence: i64, due_day: i64, cat: i64, paid: i64) -> i64 { 49 let buf: *i64 = sys_mmap(8 * (1 + BS_MAX * BS_FIELDS)) as *i64 50 let n: i64 = bs_load_raw(prefix, respondent, buf) 51 if n >= BS_MAX { return 0 - 3 } 52 let base: i64 = 1 + n * BS_FIELDS 53 buf[base + 0] = amount 54 buf[base + 1] = cadence 55 buf[base + 2] = due_day 56 buf[base + 3] = cat 57 buf[base + 4] = paid 58 buf[0] = n + 1 59 let nbytes: i64 = (1 + (n + 1) * BS_FIELDS) * 8 60 let key: *u8 = sys_mmap(256) 61 bs_key(respondent, key) 62 let w: *i64 = ss_begin() 63 if ss_add(w, 1, key, buf as *u8, nbytes) != 0 { return 0 - 1 } 64 if ss_commit(prefix, w, sys_now_us()) != 0 { return 0 - 2 } 65 return 0 66} 67 68// how many bills the respondent has stored. 69func bs_count(prefix: *u8, respondent: *u8) -> i64 { 70 let buf: *i64 = sys_mmap(8 * (1 + BS_MAX * BS_FIELDS)) as *i64 71 return bs_load_raw(prefix, respondent, buf) 72} 73 74// load a respondent's bills into the parallel arrays the nx_bills engine consumes. returns the count. 75func bs_load(prefix: *u8, respondent: *u8, out_amount: *i64, out_cadence: *i64, out_dueday: *i64, out_cat: *i64, out_paid: *i64, cap: i64) -> i64 { 76 let buf: *i64 = sys_mmap(8 * (1 + BS_MAX * BS_FIELDS)) as *i64 77 let n: i64 = bs_load_raw(prefix, respondent, buf) 78 var i: i64 = 0 79 while i < n { 80 if i < cap { 81 let base: i64 = 1 + i * BS_FIELDS 82 out_amount[i] = buf[base + 0] 83 out_cadence[i] = buf[base + 1] 84 out_dueday[i] = buf[base + 2] 85 out_cat[i] = buf[base + 3] 86 out_paid[i] = buf[base + 4] 87 } 88 i = i + 1 89 } 90 return n 91}