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}