nx_wflow_text_identity_candidate_t344.nx source
↩ module page · 231 lines · 14349 B
1// Owned variable substitution over one immutable ledger snapshot.
2// Allocation follows measured output; compatibility wrappers never return partial success.
3struct WfVarSpan {start:i64,len:i64,found:i64}
4struct WfOwnedText {data:*u8,len:i64,bytes:i64,status:i64}
5const WF_TEXT_I64_MAX:i64=9223372036854775807
6func wf_text_match(buf:*u8,at:i64,end:i64,text:*u8,n:i64)->i64{
7 if at<0{return 0};if n<0{return 0};if at>end{return 0};if n>end-at{return 0}
8 var i:i64=0;while i<n{if buf[at+i]!=text[i]{return 0};i=i+1};return 1
9}
10func wf_var_span(buf:*u8,n:i64,rid:*u8,key:*u8,kn:i64,out:*WfVarSpan)->i64{
11 out.start=0;out.len=0;out.found=0
12 let rn:i64=slen(rid);var ls:i64=0
13 while ls<n{
14 var le:i64=ls;while le<n{if buf[le]==(10 as u8){break};le=le+1}
15 var at:i64=ls
16 var matched:i64=wf_text_match(buf,at,le,"WFVAR rid=",slen("WFVAR rid="))
17 if matched==1{at=at+slen("WFVAR rid=");matched=wf_text_match(buf,at,le,rid,rn)}
18 if matched==1{at=at+rn;matched=wf_text_match(buf,at,le," k=",slen(" k="))}
19 if matched==1{at=at+slen(" k=");matched=wf_text_match(buf,at,le,key,kn)}
20 if matched==1{at=at+kn;matched=wf_text_match(buf,at,le," v=",slen(" v="))}
21 if matched==1{at=at+slen(" v=");out.start=at;out.len=le-at;out.found=1}
22 ls=le+1
23 }
24 return out.found
25}
26func wf_text_new(n:i64,status:i64)->*WfOwnedText{
27 if n<0{return 0 as *WfOwnedText};if n==WF_TEXT_I64_MAX{return 0 as *WfOwnedText}
28 let out:*WfOwnedText=sys_mmap_try(__size_of(WfOwnedText)) as *WfOwnedText
29 if (out as i64)<=0{return 0 as *WfOwnedText}
30 out.data=sys_mmap_try(n+1)
31 if (out.data as i64)<=0{sys_munmap_direct(out as *u8,__size_of(WfOwnedText));return 0 as *WfOwnedText}
32 out.len=n;out.bytes=n+1;out.status=status;out.data[n]=0;return out
33}
34func wf_text_free(out:*WfOwnedText)->i64{
35 if out==(0 as *WfOwnedText){return 0}
36 let rc:i64=sys_munmap_direct(out.data,out.bytes)
37 let rr:i64=sys_munmap_direct(out as *u8,__size_of(WfOwnedText))
38 if rc!=0{return 0-1};return rr
39}
40func wf_var_owned(cx:*i64,rid:*u8,key:*u8)->*WfOwnedText{
41 let sz:*i64=sys_mmap_try(__size_of(i64)) as *i64
42 if (sz as i64)<=0{return 0 as *WfOwnedText}
43 let buf:*u8=wf_read_snapshot(cx[2] as *u8,sz)
44 if buf==(0 as *u8){sys_munmap_direct(sz as *u8,__size_of(i64));return 0 as *WfOwnedText}
45 let span:*WfVarSpan=sys_mmap_try(__size_of(WfVarSpan)) as *WfVarSpan
46 if (span as i64)<=0{sys_munmap_direct(buf,sz[0]+1);sys_munmap_direct(sz as *u8,__size_of(i64));return 0 as *WfOwnedText}
47 let found:i64=wf_var_span(buf,sz[0],rid,key,slen(key),span)
48 let out:*WfOwnedText=wf_text_new(span.len,found)
49 if out!=(0 as *WfOwnedText){var i:i64=0;while i<span.len{out.data[i]=buf[span.start+i];i=i+1}}
50 sys_munmap_direct(span as *u8,__size_of(WfVarSpan));sys_munmap_direct(buf,sz[0]+1);sys_munmap_direct(sz as *u8,__size_of(i64))
51 return out
52}
53func wf_subst_pass(buf:*u8,n:i64,rid:*u8,src:*u8,span:*WfVarSpan,out:*u8,cap:i64)->i64{
54 var i:i64=0;var count:i64=0
55 while src[i]!=(0 as u8){
56 var data:*u8=((src as i64)+i) as *u8
57 var len:i64=1
58 if src[i]==(123 as u8){
59 let start:i64=i+1;var end:i64=start
60 while src[end]!=(0 as u8){if src[end]==(125 as u8){break};end=end+1}
61 if src[end]==(0 as u8){return 0-1}
62 if wf_var_span(buf,n,rid,((src as i64)+start) as *u8,end-start,span)!=1{return 0-1}
63 data=((buf as i64)+span.start) as *u8;len=span.len;i=end+1
64 }else{i=i+1}
65 if len>WF_TEXT_I64_MAX-count{return 0-1}
66 if out!=(0 as *u8){
67 if count>cap{return 0-1};if len>cap-count{return 0-1}
68 var j:i64=0;while j<len{out[count+j]=data[j];j=j+1}
69 }
70 count=count+len
71 }
72 return count
73}
74func wf_subst_owned(cx:*i64,rid:*u8,src:*u8)->*WfOwnedText{
75 let sz:*i64=sys_mmap_try(__size_of(i64)) as *i64
76 if (sz as i64)<=0{return 0 as *WfOwnedText}
77 let buf:*u8=wf_read_snapshot(cx[2] as *u8,sz)
78 if buf==(0 as *u8){sys_munmap_direct(sz as *u8,__size_of(i64));return 0 as *WfOwnedText}
79 let span:*WfVarSpan=sys_mmap_try(__size_of(WfVarSpan)) as *WfVarSpan
80 if (span as i64)<=0{sys_munmap_direct(buf,sz[0]+1);sys_munmap_direct(sz as *u8,__size_of(i64));return 0 as *WfOwnedText}
81 let n:i64=wf_subst_pass(buf,sz[0],rid,src,span,0 as *u8,0)
82 var out:*WfOwnedText=0 as *WfOwnedText
83 if n>=0{
84 out=wf_text_new(n,1)
85 if out!=(0 as *WfOwnedText){
86 if wf_subst_pass(buf,sz[0],rid,src,span,out.data,n)!=n{wf_text_free(out);out=0 as *WfOwnedText}
87 }
88 }
89 sys_munmap_direct(span as *u8,__size_of(WfVarSpan));sys_munmap_direct(buf,sz[0]+1);sys_munmap_direct(sz as *u8,__size_of(i64))
90 if out==(0 as *WfOwnedText){p("WFLOW substitution ERROR unresolved input or allocation; no partial result\n")}
91 return out
92}
93
94func wf_text_slice(src:*u8,start:i64,n:i64)->*WfOwnedText{
95 let out:*WfOwnedText=wf_text_new(n,1)
96 if out==(0 as *WfOwnedText){return out}
97 var i:i64=0;while i<n{out.data[i]=src[start+i];i=i+1};return out
98}
99func wf_text_decimal(v:i64)->*WfOwnedText{
100 if v<0{return 0 as *WfOwnedText}
101 var n:i64=1;var q:i64=v;while q>=10{n=n+1;q=q/10}
102 let out:*WfOwnedText=wf_text_new(n,1)
103 if out==(0 as *WfOwnedText){return out}
104 q=v;var i:i64=n
105 while i>0{i=i-1;out.data[i]=(48+q%10) as u8;q=q/10};return out
106}
107
108struct WfRunFields {fid:*u8,index:*u8,action:*u8,channel:*u8,arg:*u8,retry:*u8,condition:*u8,onfail:*u8}
109struct WfRunScratch {fields:*WfRunFields,cap:i64,prepared:*WfOwnedText}
110func wf_run_scratch_free(s:*WfRunScratch)->i64{
111 if s==(0 as *WfRunScratch){return 0}
112 var rc:i64=wf_text_free(s.prepared)
113 if s.fields!=(0 as *WfRunFields){
114 let slots:*i64=s.fields as *i64;var i:i64=0
115 while i<__size_of(WfRunFields)/__size_of(i64){if slots[i]>0{if sys_munmap_direct(slots[i] as *u8,s.cap)!=0{rc=WF_EVIDENCE_ERROR}};i=i+1}
116 if sys_munmap_direct(s.fields as *u8,__size_of(WfRunFields))!=0{rc=WF_EVIDENCE_ERROR}
117 }
118 if sys_munmap_direct(s as *u8,__size_of(WfRunScratch))!=0{rc=WF_EVIDENCE_ERROR};return rc
119}
120func wf_run_scratch_new(cap:i64)->*WfRunScratch{
121 if cap<=0{return 0 as *WfRunScratch}
122 let s:*WfRunScratch=sys_mmap_try(__size_of(WfRunScratch)) as *WfRunScratch
123 if (s as i64)<=0{return 0 as *WfRunScratch}
124 s.cap=cap;s.prepared=0 as *WfOwnedText
125 s.fields=sys_mmap_try(__size_of(WfRunFields)) as *WfRunFields
126 if (s.fields as i64)<=0{s.fields=0 as *WfRunFields;wf_run_scratch_free(s);return 0 as *WfRunScratch}
127 let slots:*i64=s.fields as *i64;var i:i64=0
128 while i<__size_of(WfRunFields)/__size_of(i64){
129 let buf:*u8=sys_mmap_try(cap)
130 if (buf as i64)<=0{wf_run_scratch_free(s);return 0 as *WfRunScratch}
131 slots[i]=buf as i64;i=i+1
132 }
133 return s
134}
135
136// Complete token fields use owned storage; callers never receive a successful prefix.
137func wf_id_token_ok(s:*u8)->i64{var i:i64=0;while s[i]!=0{if s[i]<=(32 as u8)||s[i]==(127 as u8){return 0};i=i+1};return (i>0) as i64}
138func wf_id_event(ev:*u8)->*WfOwnedText{
139 let n:i64=slen(ev);var count:i64=0;var start:i64=0;var len:i64=0;var i:i64=0
140 while i<n{if ev[i]<(32 as u8)||ev[i]==(127 as u8){return 0 as *WfOwnedText}
141 if wf_text_match(ev,i,n,"~id=",4)==1{count=count+1;start=i+4;var end:i64=start;while end<n{if ev[end]==(126 as u8){break};if ev[end]<=(32 as u8)||ev[end]==(127 as u8){return 0 as *WfOwnedText};end=end+1};len=end-start};i=i+1}
142 if count!=1||len<1{return 0 as *WfOwnedText};return wf_text_slice(ev,start,len)
143}
144func wf_id_field(buf:*u8,start:i64,end:i64,key:*u8)->*WfOwnedText{
145 let kn:i64=slen(key);var at:i64=start
146 while at<end{if wf_text_match(buf,at,end,key,kn)==1{let a:i64=at+kn;var b:i64=a;while b<end{if buf[b]<=(32 as u8){break};b=b+1};return wf_text_slice(buf,a,b-a)};at=at+1};return wf_text_new(0,0)
147}
148func wf_id_pipe(row:*u8,index:i64)->*WfOwnedText{
149 let n:i64=slen(row);var start:i64=0;var part:i64=0;var i:i64=0
150 while i<=n{if i==n||row[i]==(124 as u8){if part==index{return wf_text_slice(row,start,i-start)};part=part+1;start=i+1};i=i+1};return wf_text_new(0,0)
151}
152func wf_id_join(a:*u8,sep:*u8,b:*u8)->*WfOwnedText{
153 let an:i64=slen(a);let sn:i64=slen(sep);let bn:i64=slen(b)
154 if an>WF_TEXT_I64_MAX-sn{return 0 as *WfOwnedText};let pre:i64=an+sn;if bn>WF_TEXT_I64_MAX-pre{return 0 as *WfOwnedText}
155 let out:*WfOwnedText=wf_text_new(pre+bn,1);if out==(0 as *WfOwnedText){return out}
156 var p:i64=wf_cat(out.data,0,a);p=wf_cat(out.data,p,sep);wf_cat(out.data,p,b);return out
157}
158func wf_id_hex(e:*u8,f:*u8)->*WfOwnedText{
159 let en:i64=slen(e);let fn:i64=slen(f);if en>WF_TEXT_I64_MAX-fn{return 0 as *WfOwnedText};let n:i64=en+fn
160 if n>(WF_TEXT_I64_MAX-4)/2{return 0 as *WfOwnedText};let out:*WfOwnedText=wf_text_new(4+n*2,1);if out==(0 as *WfOwnedText){return out}
161 let digits:*u8="0123456789abcdef";var at:i64=wf_cat(out.data,0,"v2:");var i:i64=0
162 while i<en{let c:i64=e[i] as i64;out.data[at]=digits[c/16];out.data[at+1]=digits[c%16];at=at+2;i=i+1};out.data[at]=58 as u8;at=at+1;i=0
163 while i<fn{let c:i64=f[i] as i64;out.data[at]=digits[c/16];out.data[at+1]=digits[c%16];at=at+2;i=i+1};return out
164}
165func wf_id_binding(buf:*u8,n:i64,rid:*u8,event:*u8,flow:*u8,version:i64)->i64{
166 var starts:i64=0;var bindings:i64=0;var bound:i64=0;var ls:i64=0;let rn:i64=slen(rid)
167 while ls<n{var le:i64=ls;while le<n{if buf[le]==(10 as u8){break};le=le+1}
168 if le==n{return 0-1}
169 if wf_text_match(buf,ls,le,"WFRUN rid=",10)==1{
170 let r:*WfOwnedText=wf_id_field(buf,ls,le," rid=");if r==(0 as *WfOwnedText){return 0-1}
171 if seq(r.data,rid)==1{
172 let st:*WfOwnedText=wf_id_field(buf,ls,le," status=");if st==(0 as *WfOwnedText){wf_text_free(r);return 0-1}
173 if seq(st.data,"BOUND")==1{if starts!=1||bindings!=1{wf_text_free(st);wf_text_free(r);return 0-1};bound=bound+1}
174 if seq(st.data,"START")==1{
175 starts=starts+1;let fid:*WfOwnedText=wf_id_field(buf,ls,le," flow=");let v:*WfOwnedText=wf_id_field(buf,ls,le," identity=")
176 if fid==(0 as *WfOwnedText)||v==(0 as *WfOwnedText){wf_text_free(fid);wf_text_free(v);wf_text_free(st);wf_text_free(r);return 0-1}
177 var ok:i64=seq(fid.data,flow);if version==2{if seq(v.data,"2")!=1{ok=0}}else{if v.len>0{ok=0}}
178 wf_text_free(fid);wf_text_free(v);if ok!=1{wf_text_free(st);wf_text_free(r);return 0-1}
179 };wf_text_free(st)
180 };wf_text_free(r)
181 }
182 if wf_text_match(buf,ls,le,"WFVAR rid=",10)==1&&wf_text_match(buf,ls+10,le,rid,rn)==1&&wf_text_match(buf,ls+10+rn,le," k=id v=",8)==1{
183 if starts!=1||bound!=0{return 0-1};bindings=bindings+1;let at:i64=ls+10+rn+8;if le-at!=slen(event)||wf_text_match(buf,at,le,event,slen(event))!=1{return 0-1}
184 };ls=le+1
185 };if starts==0{return 0};if starts!=1||bindings!=1{return 0-1};if version==2&&bound!=1{return 0-1};return 1
186}
187
188func wf_id_alloc(a:*u8,b:*u8,c:*u8,d:*u8,extra:i64)->*WfOwnedText{
189 var n:i64=extra;let lens:*i64=sys_mmap_try(__size_of(i64)*4) as *i64;if (lens as i64)<=0{return 0 as *WfOwnedText};lens[0]=slen(a);lens[1]=slen(b);lens[2]=slen(c);lens[3]=slen(d);var i:i64=0
190 while i<4{if lens[i]>WF_TEXT_I64_MAX-n{sys_munmap_direct(lens as *u8,__size_of(i64)*4);return 0 as *WfOwnedText};n=n+lens[i];i=i+1};sys_munmap_direct(lens as *u8,__size_of(i64)*4);if n<=0{return 0 as *WfOwnedText};return wf_text_new(n-1,1)
191}
192func wf_id_tok(rid:*u8)->*WfOwnedText{return wf_id_join(" rid=",rid," ")}
193func wf_emit_start2(led:*u8,rid:*u8,fid:*u8)->i64{
194 let record:*WfOwnedText=wf_id_alloc(rid,fid,"","",slen("WFRUN rid= flow= step=0 status=START att=0 identity=2\n")+1)
195 if record==(0 as *WfOwnedText){return WF_EVIDENCE_ERROR};let line:*u8=record.data;var at:i64=wf_cat(line,0,"WFRUN rid=");at=wf_cat(line,at,rid);at=wf_cat(line,at," flow=");at=wf_cat(line,at,fid);at=wf_cat(line,at," step=0 status=START att=0 identity=2\n");line[at]=0
196 let rc:i64=wf_append(led,line);wf_text_free(record);return rc
197}
198func wf_fire_pair(cx:*i64,buf:*u8,n:i64,event:*u8,ev:*u8,fid:*u8)->i64{
199 if wf_id_token_ok(fid)!=1{return WF_EVIDENCE_ERROR}
200 // Historical v1 serialization widths are used only to locate immutable legacy records.
201 var en:i64=slen(event);if en>127{en=127};var fn:i64=slen(fid);if fn>63{fn=63}
202 let olde:*WfOwnedText=wf_text_slice(event,0,en);let oldf:*WfOwnedText=wf_text_slice(fid,0,fn)
203 if olde==(0 as *WfOwnedText)||oldf==(0 as *WfOwnedText){wf_text_free(olde);wf_text_free(oldf);return WF_EVIDENCE_ERROR}
204 let legacy:*WfOwnedText=wf_id_join(olde.data,".",oldf.data);wf_text_free(olde);wf_text_free(oldf);if legacy==(0 as *WfOwnedText){return WF_EVIDENCE_ERROR}
205 let old:i64=wf_id_binding(buf,n,legacy.data,event,fid,0);wf_text_free(legacy)
206 if old<0{p("WFLOW identity ERROR legacy binding uncertain; no dispatch\n");return WF_EVIDENCE_ERROR};if old==1{return 0}
207 let rid:*WfOwnedText=wf_id_hex(event,fid);if rid==(0 as *WfOwnedText){return WF_EVIDENCE_ERROR}
208 let known:i64=wf_id_binding(buf,n,rid.data,event,fid,2)
209 if known<0{wf_text_free(rid);p("WFLOW identity ERROR namespace or incomplete binding; no dispatch\n");return WF_EVIDENCE_ERROR};if known==1{wf_text_free(rid);return 0}
210 let led:*u8=cx[2] as *u8;var rc:i64=wf_emit_start2(led,rid.data,fid)
211 if rc==0&&cx[4]>0{rc=wf_emit_ver(led,rid.data,cx[4])}
212 if rc==0{if wf_bind_event(cx,rid.data,ev)<0{rc=WF_EVIDENCE_ERROR}}
213 if rc==0{rc=wf_emit(led,rid.data,fid,0,"BOUND",0)}
214 if rc==0{let run:i64=wf_run_from(cx,rid.data,fid,0);if run==WF_EVIDENCE_ERROR{rc=run}}
215 if wf_text_free(rid)!=0{return WF_EVIDENCE_ERROR};if rc!=0{return WF_EVIDENCE_ERROR};return 1
216}
217
218func wf_id_replay_binding(buf:*u8,n:i64,rid:*u8,fid:*u8)->i64{
219 let span:*WfVarSpan=sys_mmap_try(__size_of(WfVarSpan)) as *WfVarSpan;if (span as i64)<=0{return 0-1}
220 let found:i64=wf_var_span(buf,n,rid,"id",2,span);if found!=1{sys_munmap_direct(span as *u8,__size_of(WfVarSpan));return 0-1}
221 let event:*WfOwnedText=wf_text_slice(buf,span.start,span.len);sys_munmap_direct(span as *u8,__size_of(WfVarSpan));if event==(0 as *WfOwnedText){return 0-1}
222 let v2:*WfOwnedText=wf_id_hex(event.data,fid);if v2==(0 as *WfOwnedText){wf_text_free(event);return 0-1}
223 var version:i64=0;if seq(v2.data,rid)==1{version=2};wf_text_free(v2)
224 let rc:i64=wf_id_binding(buf,n,rid,event.data,fid,version);wf_text_free(event);return rc
225}
226
227func wf_id_html(s:*u8)->*WfOwnedText{
228 var n:i64=0;var i:i64=0;while s[i]!=0{var add:i64=1;if s[i]==(38 as u8){add=slen("&")};if s[i]==(60 as u8){add=slen("<")};if s[i]==(62 as u8){add=slen(">")};if add>WF_TEXT_I64_MAX-n{return 0 as *WfOwnedText};n=n+add;i=i+1}
229 let out:*WfOwnedText=wf_text_new(n,1);if out==(0 as *WfOwnedText){return out};i=0;var p:i64=0
230 while s[i]!=0{if s[i]==(38 as u8){p=wf_cat(out.data,p,"&")}else{if s[i]==(60 as u8){p=wf_cat(out.data,p,"<")}else{if s[i]==(62 as u8){p=wf_cat(out.data,p,">")}else{out.data[p]=s[i];p=p+1}}};i=i+1};return out
231}