code wiki / (root) / nx_wflow_ownership_old_text_fixture_t344.nx

nx_wflow_ownership_old_text_fixture_t344.nx source

↩ module page · 231 lines · 14320 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 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)->*u8{ 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 *u8};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 *u8};n=n+lens[i];i=i+1};sys_munmap_direct(lens as *u8,__size_of(i64)*4);if n<=0{return 0 as *u8};let out:*u8=sys_mmap_try(n);if (out as i64)<=0{return 0 as *u8};return out 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 line:*u8=wf_id_alloc(rid,fid,"","",slen("WFRUN rid= flow= step=0 status=START att=0 identity=2\n")+1) 195 if line==(0 as *u8){return WF_EVIDENCE_ERROR};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);if sys_munmap_direct(line,at+1)!=0{return WF_EVIDENCE_ERROR};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("&amp;")};if s[i]==(60 as u8){add=slen("&lt;")};if s[i]==(62 as u8){add=slen("&gt;")};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,"&amp;")}else{if s[i]==(60 as u8){p=wf_cat(out.data,p,"&lt;")}else{if s[i]==(62 as u8){p=wf_cat(out.data,p,"&gt;")}else{out.data[p]=s[i];p=p+1}}};i=i+1};return out 231}