~/bend-docscommunity

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.

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.

type Span source · line 24 · raw

Data

Reader ------ A field's bytes are src[s..e]. esc says the field was quoted and holds "".

type Scan source · line 28 · raw

Data

Spans are latest first.

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.

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.