csv.bend checks
raw source on the hub · import 0xc44bda2e3431d17209e2df2adb8b59d8/csv.bend as Csv
CSV (RFC 4180) over bytes: a record cursor, a whole-document parse, and an encoder. Source: https://github.com/paymog/bend-kit/tree/main/csv
2 imports
import Base import 0x49814d83de8f70993a43e1002be29ecd/bytes.bend as Bytes
Types
type Cur source · line 11 · raw
Type
The unread bytes and the offset of the next record.
Cur@src:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @at:U32 -> Cur
type Next source · line 16 · raw
Type
One step of the cursor: a record and the cursor after it, the end of input, or the offset of the first byte that breaks RFC 4180.
Row@fields:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> @cur:Cur -> Next
EndNext
Bad@at:U32 -> Next
type Span source · line 24 · raw
Data
Reader ------ A field's bytes are src[s..e]. esc says the field was quoted and holds "".
Span@s:U32 -> @e:U32 -> @esc:Bool -> Span
type Scan source · line 28 · raw
Data
Spans are latest first.
SRow@sp:List<&2, Span> -> @at:U32 -> Scan
SBad@at:U32 -> Scan
type St source · line 34 · raw
Data
Start: before a field. Unq: in an unquoted field. Q: in a quoted field. QQ: just past a quote inside a quoted field. CR: just past a record's CR.
SStartSt
SUnqSt
SQSt
SQQSt
SCRSt
Definitions
def pk.if source · line 42 · raw
@ok:Bool -> @a:Array<U32> -> @+i:U32 -> Pair(Array<U32>, U32)
Byte i, or 256 past the end.
def pk source · line 49 · raw
@a:Array<U32> -> @+len:U32 -> @+i:U32 -> Pair(Array<U32>, U32)
def start.sp source · line 53 · raw
@sp:List<&2, Span> -> @+i:U32 -> List<&2, Span>
An empty line has no fields; a trailing comma adds an empty field.
def rec.go source · line 62 · raw
@f:Nat -> @st:St -> @r:Pair(Array<U32>, U32) -> @+len:U32 -> @+i:U32 -> @+s:U32 -> @+esc:Bool -> @+sp:List<&2, Span> -> Pair(Array<U32>, Scan)
r holds byte i. s is where the open field starts. Every step but the last reads one byte.
def q source · line 131 · raw
0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes
def qq source · line 134 · raw
0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes
def unq.go source · line 138 · raw
@xs:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> @acc:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
Pieces between "" pairs, latest first, with one quote between each.
def unq.of source · line 145 · raw
@xs:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes
def field.of source · line 153 · raw
@esc:Bool -> @b:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes
A quoted field's inner bytes with each "" as one quote. Quotes inside come in pairs.
def cut.fin source · line 160 · raw
@+m:U32 -> @+esc:Bool -> @r:Pair(Array<U32>, Array<U32>) -> @acc:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> Pair(Array<U32>, List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>)
def cut.go source · line 165 · raw
@sp:List<&2, Span> -> @r:Pair(Array<U32>, List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>) -> Pair(Array<U32>, List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>)
Spans latest first give fields in order.
def next.fin source · line 174 · raw
@+len:U32 -> @+at:U32 -> @r:Pair(Array<U32>, List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>) -> Next
def next.row source · line 178 · raw
@+len:U32 -> @r:Pair(Array<U32>, Scan) -> Next
def next.if source · line 186 · raw
@more:Bool -> @+len:U32 -> @buf:Array<U32> -> @+at:U32 -> Next
def cursor source · line 194 · raw
@b:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Cur
A cursor at the first record.
def next source · line 198 · raw
@c:Cur -> Next
The next record, End at the end of input, or Bad with the offset of the first bad byte.
def parse.go source · line 203 · raw
@f:Nat -> @nx:Next -> @acc:List<&1, List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>> -> Result<&1, &1, U32, List<&1, List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>>>
Each record reads at least one byte, so len + 1 steps are enough.
def parse source · line 217 · raw
@b:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Result<&1, &1, U32, List<&1, List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>>>
Every record, or Fail with the offset of the first bad byte.
def needs.go source · line 224 · raw
@n:Nat -> @r:Pair(Array<U32>, U32) -> @+i:U32 -> Pair(Array<U32>, Bool)
Writer ------ Does a byte from i on need quotes? n counts the bytes left.
def enc.rest source · line 244 · raw
@xs:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> @acc:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
The pieces after the first, each after "".
def enc.parts source · line 251 · raw
@xs:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> @acc:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
def enc.pick source · line 258 · raw
@+len:U32 -> @r:Pair(Array<U32>, Bool) -> @acc:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
def enc.field source · line 267 · raw
@f:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @acc:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
Pieces are latest first. A field is quoted only when it holds a quote, comma, CR, or LF.
def enc.more source · line 271 · raw
@fs:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> @acc:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
def enc.only.if source · line 278 · raw
@empty:Bool -> @f:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @acc:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
def enc.only source · line 285 · raw
@f:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @acc:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
def enc.fields source · line 290 · raw
@fs:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> @acc:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
def enc.recs source · line 299 · raw
@rs:List<&1, List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>> -> @acc:List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
def encode source · line 307 · raw
@rs:List<&1, List<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>> -> 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes
Records as RFC 4180 text: fields joined by commas, each record ended by CRLF.