json.bend checks
raw source on the hub · import bend-kit-json@0.5.1.0/json.bend as Json
JSON values, parsed and encoded as RFC 8259. Source: https://github.com/paymog/bend-kit/tree/main/json
2 imports
import Base import 0x49814d83de8f70993a43e1002be29ecd/bytes.bend as Bytes
Types
type Val source · line 12 · raw
Type
Num keeps the number's exact text, so no precision is lost. Obj keeps its fields in document order, repeated keys included.
NullVal
Flag@on:Bool -> Val
Num@s:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Val
Str@s:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Val
Arr@xs:List<&1, Val> -> Val
Obj@kvs:List<&1, Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, Val)> -> Val
type Open source · line 22 · raw
Type
An open container: array items so far, object fields so far, or those fields and the key whose value comes next. Items and fields are reversed.
OArr@xs:List<&1, Val> -> Open
OObj@kvs:List<&1, Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, Val)> -> Open
OKey@kvs:List<&1, Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, Val)> -> @key:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Open
type W source · line 31 · raw
Type
Writer ------ Octets being written: the buffer, its size in words, the count so far, and the word being filled. Bytes enter at the top of w, as in Bytes.from_string.
W@buf:Array<U32> -> @cap:U32 -> @n:U32 -> @w:U32 -> W
type Sb source · line 165 · raw
Type
BValue@i:U32 -> @stack:List<&1, Open> -> Sb
BFirst@i:U32 -> @open:Open -> @stack:List<&1, Open> -> Sb
BKey@i:U32 -> @stack:List<&1, Open> -> Sb
BColon@key:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @i:U32 -> @stack:List<&1, Open> -> Sb
BStr@i:U32 -> @start:U32 -> @key:Bool -> @stack:List<&1, Open> -> Sb
BEsc@i:U32 -> @acc:W -> @key:Bool -> @stack:List<&1, Open> -> Sb
BNum@i:U32 -> @start:U32 -> @st:U32 -> @stack:List<&1, Open> -> Sb
BAfter@v:Val -> @i:U32 -> @stack:List<&1, Open> -> Sb
BSep@i:U32 -> @open:Open -> @stack:List<&1, Open> -> Sb
BEnd@v:Val -> @i:U32 -> Sb
BOk@v:Val -> Sb
BFailSb
type Cp source · line 179 · raw
Data
Cp@c:U32 -> @w:U32 -> Cp
Definitions
def w.room source · line 35 · raw
@grow:Bool -> @buf:Array<U32> -> @+k:U32 -> Array<U32>
The buffer doubles when word k does not fit.
def w.store source · line 42 · raw
@full:Bool -> @buf:Array<U32> -> @+cap:U32 -> @+n:U32 -> @+w:U32 -> W
def w.put source · line 51 · raw
@o:W -> @+b:U32 -> W
def w.shrink source · line 55 · raw
@fit:Bool -> @+n:U32 -> @buf:Array<U32> -> Array<U32>
def w.done source · line 63 · raw
@o:W -> 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes
Stores the last partial word, then copies into the fewest words, as Bytes requires.
def w.cont source · line 72 · raw
@+c:U32 -> @+k:Nat -> U32
def w.cp.of source · line 75 · raw
@+n:U32 -> @+c:U32 -> @o:W -> W
def w.cp source · line 87 · raw
@+c:U32 -> @o:W -> W
One code point in UTF-8.
def w.hex source · line 90 · raw
@+n:U32 -> U32
def w.new source · line 93 · raw
W
def w.of.at source · line 96 · raw
@+len:U32 -> @+cap:U32 -> @r:Pair(Array<U32>, U32) -> W
def w.of source · line 102 · raw
@b:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> W
A writer that appends to b.
def w.text source · line 106 · raw
@s:String -> @o:W -> W
def utf8 source · line 114 · raw
@s:String -> 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes
Text, one Char per code point, as UTF-8.
def digit source · line 123 · raw
@+c:U32 -> Bool
def num.trans source · line 126 · raw
@+st:U32 -> @+c:U32 -> U32
def num.accepts source · line 139 · raw
@+st:U32 -> Bool
def hexd source · line 145 · raw
@+c:U32 -> U32
def is_hi source · line 148 · raw
@+v:U32 -> Bool
def is_lo source · line 151 · raw
@+v:U32 -> Bool
def esc.simple source · line 154 · raw
@+e:U32 -> U32
def pk.if source · line 182 · raw
@ok:Bool -> @a:Array<U32> -> @+i:U32 -> Pair(Array<U32>, U32)
def pk source · line 190 · raw
@a:Array<U32> -> @+len:U32 -> @+i:U32 -> Pair(Array<U32>, U32)
Byte i, or 256 at the end, which no rule accepts.
def is_ws source · line 193 · raw
@+c:U32 -> Bool
def plain source · line 197 · raw
@+c:U32 -> Bool
A string byte that needs no check: ASCII, not a control, quote or backslash.
def pos.of source · line 200 · raw
@+i:U32 -> @r:Pair(Array<U32>, U32) -> Pair(Array<U32>, Pair(U32, U32))
def pos source · line 205 · raw
@a:Array<U32> -> @+len:U32 -> @+i:U32 -> Pair(Array<U32>, Pair(U32, U32))
The offset i and its byte.
def word.go source · line 230 · raw
@w:String -> @ok:Bool -> @r:Pair(Array<U32>, U32) -> @+len:U32 -> @+j:U32 -> Pair(Array<U32>, Bool)
def word source · line 240 · raw
@a:Array<U32> -> @+len:U32 -> @w:String -> @+j:U32 -> Pair(Array<U32>, Bool)
Do the bytes from j spell w?
def hex4.b.go source · line 243 · raw
@n:Nat -> @r:Pair(Array<U32>, U32) -> @+len:U32 -> @+j:U32 -> @+acc:U32 -> Pair(Array<U32>, U32)
def hex4.b source · line 254 · raw
@a:Array<U32> -> @+len:U32 -> @+j:U32 -> Pair(Array<U32>, U32)
Four hex digits from byte j, or 65536 if one is not a hex digit.
def cont source · line 257 · raw
@+b:U32 -> Bool
def utf8.n source · line 261 · raw
@+b0:U32 -> @+b1:U32 -> @+b2:U32 -> @+b3:U32 -> Cp
RFC 3629 §4: overlong forms, surrogates, and code points past U+10FFFF are invalid, width 0.
def utf8.b3 source · line 273 · raw
@+b0:U32 -> @+b1:U32 -> @+b2:U32 -> @r:Pair(Array<U32>, U32) -> Pair(Array<U32>, Cp)
def utf8.b2 source · line 277 · raw
@+len:U32 -> @+i:U32 -> @+b0:U32 -> @+b1:U32 -> @r:Pair(Array<U32>, U32) -> Pair(Array<U32>, Cp)
def utf8.b1 source · line 281 · raw
@+len:U32 -> @+i:U32 -> @+b0:U32 -> @r:Pair(Array<U32>, U32) -> Pair(Array<U32>, Cp)
def utf8.at source · line 286 · raw
@a:Array<U32> -> @+len:U32 -> @+i:U32 -> @+b0:U32 -> Pair(Array<U32>, Cp)
The code point whose lead byte b0 is at i.
def slice.of source · line 289 · raw
@+n:U32 -> @r:Pair(Array<U32>, Array<U32>) -> Pair(Array<U32>, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes)
def slice source · line 294 · raw
@+n:U32 -> @+start:U32 -> @a:Array<U32> -> Pair(Array<U32>, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes)
The n bytes from start, copied.
def str.b.done source · line 297 · raw
@key:Bool -> @s:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @+i:U32 -> @stack:List<&1, Open> -> Sb
def esc.b.lone source · line 304 · raw
@strict:Bool -> @+i:U32 -> @acc:W -> @key:Bool -> @stack:List<&1, Open> -> Sb
def esc.b.lo.if source · line 311 · raw
@ok:Bool -> @strict:Bool -> @+i:U32 -> @+hi:U32 -> @+lo:U32 -> @acc:W -> @key:Bool -> @stack:List<&1, Open> -> Sb
def esc.b.lo source · line 318 · raw
@strict:Bool -> @+i:U32 -> @+hi:U32 -> @acc:W -> @key:Bool -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, U32) -> Pair(Array<U32>, Sb)
def esc.b.pair source · line 323 · raw
@+strict:Bool -> @+len:U32 -> @+i:U32 -> @+hi:U32 -> @acc:W -> @key:Bool -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, Bool) -> Pair(Array<U32>, Sb)
A high surrogate must pair in strict mode; RFC §8.2 mode replaces a lone one.
def u.class source · line 332 · raw
@+v:U32 -> U32
0: not four hex digits; 1: high surrogate; 2: low surrogate; 3: other.
def esc.b.u.of source · line 335 · raw
@+k:U32 -> @strict:Bool -> @a:Array<U32> -> @+len:U32 -> @+i:U32 -> @+v:U32 -> @acc:W -> @key:Bool -> @stack:List<&1, Open> -> Pair(Array<U32>, Sb)
def esc.b.u source · line 346 · raw
@strict:Bool -> @+len:U32 -> @+i:U32 -> @acc:W -> @key:Bool -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, U32) -> Pair(Array<U32>, Sb)
def esc.b.one source · line 351 · raw
@strict:Bool -> @+len:U32 -> @+i:U32 -> @acc:W -> @key:Bool -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, U32) -> Pair(Array<U32>, Sb)
The escape whose backslash is at i.
def esc.b.cp source · line 360 · raw
@acc:W -> @key:Bool -> @stack:List<&1, Open> -> @+i:U32 -> @r:Pair(Array<U32>, Cp) -> Pair(Array<U32>, Sb)
def esc.b.other source · line 365 · raw
@ascii:Bool -> @+c:U32 -> @a:Array<U32> -> @+len:U32 -> @+i:U32 -> @acc:W -> @key:Bool -> @stack:List<&1, Open> -> Pair(Array<U32>, Sb)
§7: unescaped chars below U+0020 are not allowed in a string.
def esc.b source · line 373 · raw
@strict:Bool -> @r:Pair(Array<U32>, U32) -> @+len:U32 -> @+i:U32 -> @acc:W -> @key:Bool -> @stack:List<&1, Open> -> Pair(Array<U32>, Sb)
A string after its first escape.
def str.b.close source · line 385 · raw
@key:Bool -> @+i:U32 -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes) -> Pair(Array<U32>, Sb)
def str.b.esc source · line 389 · raw
@strict:Bool -> @+len:U32 -> @+i:U32 -> @key:Bool -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes) -> Pair(Array<U32>, Sb)
def str.b.cp source · line 393 · raw
@+start:U32 -> @key:Bool -> @stack:List<&1, Open> -> @+i:U32 -> @r:Pair(Array<U32>, Cp) -> Pair(Array<U32>, Sb)
def str.b.other source · line 397 · raw
@ascii:Bool -> @+c:U32 -> @a:Array<U32> -> @+len:U32 -> @+i:U32 -> @+start:U32 -> @key:Bool -> @stack:List<&1, Open> -> Pair(Array<U32>, Sb)
def str.b source · line 405 · raw
@strict:Bool -> @r:Pair(Array<U32>, U32) -> @+len:U32 -> @+i:U32 -> @+start:U32 -> @key:Bool -> @stack:List<&1, Open> -> Pair(Array<U32>, Sb)
A string whose text so far starts at start and has no escape.
def num.b.fin source · line 417 · raw
@+i:U32 -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes) -> Pair(Array<U32>, Sb)
def num.b.stop source · line 421 · raw
@ok:Bool -> @a:Array<U32> -> @+i:U32 -> @+start:U32 -> @stack:List<&1, Open> -> Pair(Array<U32>, Sb)
def num.b.if source · line 428 · raw
@stop:Bool -> @a:Array<U32> -> @+i:U32 -> @+start:U32 -> @+st:U32 -> @+n:U32 -> @stack:List<&1, Open> -> Pair(Array<U32>, Sb)
def num.b source · line 435 · raw
@r:Pair(Array<U32>, U32) -> @+i:U32 -> @+start:U32 -> @+st:U32 -> @stack:List<&1, Open> -> Pair(Array<U32>, Sb)
def lit.b source · line 440 · raw
@+i:U32 -> @+n:U32 -> @v:Val -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, Bool) -> Pair(Array<U32>, Sb)
def value.b source · line 448 · raw
@r:Pair(Array<U32>, U32) -> @+len:U32 -> @+i:U32 -> @stack:List<&1, Open> -> Pair(Array<U32>, Sb)
def first.b.end source · line 475 · raw
@open:Open -> @+c:U32 -> @+i:U32 -> @stack:List<&1, Open> -> Sb
After "[" or "{": the closing bracket, or the first item.
def first.b.open source · line 484 · raw
@open:Open -> @+i:U32 -> @stack:List<&1, Open> -> Sb
def first.b source · line 493 · raw
@r:Pair(Array<U32>, U32) -> @+i:U32 -> @open:Open -> @stack:List<&1, Open> -> Pair(Array<U32>, Sb)
def key.b source · line 511 · raw
@r:Pair(Array<U32>, U32) -> @+i:U32 -> @stack:List<&1, Open> -> Pair(Array<U32>, Sb)
def colon.b.top source · line 527 · raw
@k:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @+i:U32 -> @stack:List<&1, Open> -> Sb
def colon.b source · line 538 · raw
@r:Pair(Array<U32>, U32) -> @k:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @+i:U32 -> @stack:List<&1, Open> -> Pair(Array<U32>, Sb)
def after.b source · line 555 · raw
@v:Val -> @+i:U32 -> @stack:List<&1, Open> -> Sb
A finished value joins its container.
def sep.b.comma source · line 566 · raw
@open:Open -> @+i:U32 -> @up:List<&1, Open> -> Sb
def sep.b.close source · line 575 · raw
@open:Open -> @+c:U32 -> @+i:U32 -> @up:List<&1, Open> -> Sb
def sep.b source · line 585 · raw
@r:Pair(Array<U32>, U32) -> @+i:U32 -> @open:Open -> @up:List<&1, Open> -> Pair(Array<U32>, Sb)
After an item: "," or the closing bracket.
def end.b source · line 601 · raw
@r:Pair(Array<U32>, U32) -> @v:Val -> @+i:U32 -> Pair(Array<U32>, Sb)
def value.r source · line 618 · raw
@+len:U32 -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, Pair(U32, U32)) -> Pair(Array<U32>, Sb)
A run's end (a, i, c) to each step. The parts bind without + (bendlang/bend#1077).
def level.r source · line 622 · raw
@depth:U32 -> @r:Pair(Array<U32>, Sb) -> Pair(Array<U32>, Pair(Sb, U32))
def first.at source · line 626 · raw
@a:Array<U32> -> @+c:U32 -> @i:U32 -> @+depth:U32 -> @open:Open -> @stack:List<&1, Open> -> Pair(Array<U32>, Pair(Sb, U32))
def first.r source · line 629 · raw
@ok:Bool -> @+depth:U32 -> @open:Open -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, Pair(U32, U32)) -> Pair(Array<U32>, Pair(Sb, U32))
def first.limit source · line 638 · raw
@cap:U32 -> @+depth:U32 -> @open:Open -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, Pair(U32, U32)) -> Pair(Array<U32>, Pair(Sb, U32))
def key.r source · line 641 · raw
@stack:List<&1, Open> -> @r:Pair(Array<U32>, Pair(U32, U32)) -> Pair(Array<U32>, Sb)
def colon.r source · line 645 · raw
@k:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, Pair(U32, U32)) -> Pair(Array<U32>, Sb)
def str.r source · line 649 · raw
@strict:Bool -> @+len:U32 -> @+s:U32 -> @key:Bool -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, Pair(U32, U32)) -> Pair(Array<U32>, Sb)
def num.r source · line 653 · raw
@+s:U32 -> @+st:U32 -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, Pair(U32, U32)) -> Pair(Array<U32>, Sb)
def sep.at source · line 657 · raw
@a:Array<U32> -> @+c:U32 -> @i:U32 -> @+depth:U32 -> @open:Open -> @up:List<&1, Open> -> Pair(Array<U32>, Pair(Sb, U32))
def sep.r source · line 660 · raw
@+depth:U32 -> @open:Open -> @up:List<&1, Open> -> @r:Pair(Array<U32>, Pair(U32, U32)) -> Pair(Array<U32>, Pair(Sb, U32))
def end.r source · line 664 · raw
@v:Val -> @r:Pair(Array<U32>, Pair(U32, U32)) -> Pair(Array<U32>, Sb)
def w.span.go source · line 668 · raw
@n:Nat -> @r:Pair(Array<U32>, U32) -> @+i:U32 -> @o:W -> Pair(Array<U32>, W)
def esc.r.go source · line 677 · raw
@strict:Bool -> @+len:U32 -> @+j:U32 -> @c:U32 -> @key:Bool -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, W) -> Pair(Array<U32>, Sb)
def esc.r source · line 682 · raw
@strict:Bool -> @+len:U32 -> @+i:U32 -> @acc:W -> @key:Bool -> @stack:List<&1, Open> -> @r:Pair(Array<U32>, Pair(U32, U32)) -> Pair(Array<U32>, Sb)
The plain bytes from i to the run's end go onto acc in one loop.
def num.run source · line 687 · raw
@loop:Bool -> @+g:Nat -> @a:Array<U32> -> @+len:U32 -> @+i:U32 -> Pair(Array<U32>, Pair(U32, U32))
States 3, 5 and 8 take digits until the number's part ends.
def runb source · line 695 · raw
@+fuel:Nat -> @r:Pair(Array<U32>, Pair(Sb, U32)) -> @+len:U32 -> @+strict:Bool -> @+cap:U32 -> Maybe<&1, Val>
fuel: a step eats a byte, or ends a number, a value, or an opening bracket, so 4 * len + 4 steps are enough.
def parse.bytes source · line 728 · raw
@b:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Maybe<&1, Val>
One JSON text in UTF-8, with RFC §8.2 surrogate replacement and input-sized depth.
def parse.strict.bytes source · line 735 · raw
@b:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @cap:U32 -> Maybe<&1, Val>
Strict UTF-8 JSON: reject lone surrogate escapes and more than cap nested arrays/objects, including empty containers. Scalars have depth zero. The limit is checked at each opening, before any contents are parsed.
def get.pick source · line 742 · raw
@v:Val -> @found:Maybe<&1, Val> -> @r:Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, Bool)) -> Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, Maybe<&1, Val>)
def get.step source · line 746 · raw
@k:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @v:Val -> @st:Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, Maybe<&1, Val>) -> Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, Maybe<&1, Val>)
def get.go source · line 750 · raw
@kvs:List<&1, Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, Val)> -> @st:Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, Maybe<&1, Val>) -> Maybe<&1, Val>
def get source · line 759 · raw
@v:Val -> @k:String -> Maybe<&1, Val>
§4: the value under key k of an object; the last one when k repeats, as most parsers do.
def at.go source · line 774 · raw
@xs:List<&1, Val> -> @n:Nat -> Maybe<&1, Val>
def at source · line 786 · raw
@v:Val -> @n:Nat -> Maybe<&1, Val>
Item n of an array.
def u32.over source · line 801 · raw
@+acc:U32 -> @+c:U32 -> Bool
def u32.dig source · line 804 · raw
@s:String -> @+acc:U32 -> @bad:Bool -> Maybe<&2, U32>
def u32.zero source · line 815 · raw
@t:String -> Maybe<&2, U32>
def u32.lead source · line 822 · raw
@+c:U32 -> @t:String -> @zero:Bool -> Maybe<&2, U32>
def u32.num source · line 829 · raw
@s:String -> Maybe<&2, U32>
def u32 source · line 837 · raw
@v:Val -> Maybe<&2, U32>
A number that is a whole U32, with no sign, fraction or exponent.
def w.ctl source · line 855 · raw
@ctl:Bool -> @+c:U32 -> @o:W -> W
def w.esc.c source · line 863 · raw
@+c:U32 -> @o:W -> W
§7: quote, backslash and control chars are escaped. Other bytes are already UTF-8.
def w.bytes.go source · line 878 · raw
@n:Nat -> @r:Pair(Array<U32>, U32) -> @+i:U32 -> @o:W -> W
def w.bytes source · line 886 · raw
@b:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @o:W -> W
def w.str.go source · line 890 · raw
@n:Nat -> @r:Pair(Array<U32>, U32) -> @+i:U32 -> @o:W -> W
def w.str source · line 899 · raw
@b:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @o:W -> W
A quoted, escaped string.
def w.lead source · line 904 · raw
@open:Bool -> @+c:U32 -> @o:W -> W
open: the container's first byte comes next; else a comma or its last byte.
def w.close source · line 911 · raw
@open:Bool -> @+a:U32 -> @+z:U32 -> @o:W -> W
def encb.go source · line 918 · raw
@v:Val -> @open:Bool -> @o:W -> W
def encode.bytes source · line 946 · raw
@v:Val -> 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes
Compact JSON in UTF-8, with object fields in their order.
Templates
template run.cls source · line 208 · raw
@-ok:(@+c:U32 -> Bool) -> @r:Pair(Array<U32>, U32) -> Pair(Array<U32>, Pair(U32, Bool))
template run.go source · line 213 · raw
@-ok:(@+c:U32 -> Bool) -> @g:Nat -> @r:Pair(Array<U32>, Pair(U32, Bool)) -> @+len:U32 -> @+i:U32 -> Pair(Array<U32>, Pair(U32, U32))
g bounds the loop; it is the parser's fuel, shared, so no count is built per run.
template run source · line 227 · raw
@-ok:(@+c:U32 -> Bool) -> @+g:Nat -> @a:Array<U32> -> @+len:U32 -> @+i:U32 -> Pair(Array<U32>, Pair(U32, U32))
The first offset from i whose byte is not ok, and that byte.