# gizlang:csv

CSV retains bytes and reuses one record's range table: no field copies in next/field/integer. text alone decodes; number reads the range in place (Text.decimalPrefix). Field ranges refer to the caller's input.

```gizlang
import * as Csv from "gizlang:csv";
```

## Types

### `CsvError`

```gizlang
type CsvError = { offset: i64; message: string; }
```

A CSV failure: the byte offset and what is wrong.

- `offset`: `i64`
- `message`: `string`

### `Field`

```gizlang
type Field = { start: i64; end: i64; escaped: bool; }
```

A field of a CSV record: where it starts and ends in the text, and whether it is quoted with escapes.

- `start`: `i64`
- `end`: `i64`
- `escaped`: `bool`

### `CsvReader`

```gizlang
type CsvReader
```

A reader of CSV text, record by record.

Opaque: create and use it through this module's functions.

### `CsvLayout`

```gizlang
type CsvLayout = { maxColumns: i64; maxFieldBytes: i64; maxRecordBytes: i64; firstRecordBytes: i64; position: i64; records: i64; firstColumns: i64; uniformRecords: i64; }
```

Scalar admission measurements for the complete prefix. Field bytes are the
retained raw content span, excluding surrounding quotes but including doubled
quotes. Record bytes include delimiters, quoting and any LF/CRLF terminator.
uniformRecords counts the consecutive prefix with firstColumns fields; it
stops at the first width mismatch, independently of later record widths.

- `maxColumns`: `i64`
- `maxFieldBytes`: `i64`
- `maxRecordBytes`: `i64`
- `firstRecordBytes`: `i64`
- `position`: `i64`
- `records`: `i64`
- `firstColumns`: `i64`
- `uniformRecords`: `i64`

### `CsvWriter`

```gizlang
type CsvWriter
```

Writer owns its output. Fields append to that buffer; escaping copies runs
and doubles quote bytes only when required. end emits RFC 4180 CRLF.

Opaque: create and use it through this module's functions.

## Functions

### `reader`

```gizlang
function reader(data: bytes): CsvReader
```

A reader of the CSV text `data`.

### `layout`

```gizlang
function layout(data: bytes, delimiter: u64, quote: u64, final: bool, maxRecords: i64): CsvLayout throws CsvError
```

Use the reader's exact grammar without retaining fields or decoding text.
A nonfinal incomplete tail contributes no measurements; malformed input
reports the same first error as nextAvailable, including in that tail.
maxRecords=0 scans the full input. A positive limit stops after that many
committed records without examining the remainder; a negative limit is invalid.

Effects: fail.

### `writer`

```gizlang
function writer(): CsvWriter
```

A writer of CSV with comma as the delimiter and `"` as the quote.

## Methods

### `CsvReader.format`

```gizlang
function CsvReader.format(self: mut CsvReader, delimiter: u64, quote: u64): bool
```

Configure before reading. Invalid configuration stops the reader as data
errors do; arbitrary distinct bytes except CR/LF are supported.

Effects: fail.

### `CsvReader.error`

```gizlang
function CsvReader.error(self: CsvReader): Option<CsvError>
```

The error that stopped the reader, if there is one.

### `CsvReader.next`

```gizlang
function CsvReader.next(self: mut CsvReader): bool
```

Empty input has no records. An empty line is one empty field; a final
delimiter adds an empty field, a final newline does not add a record.

Effects: fail.

### `CsvReader.nextAvailable`

```gizlang
function CsvReader.nextAvailable(self: mut CsvReader, final: bool): bool
```

A nonfinal byte window never commits its unfinished last record. Field ranges
and grammar are shared with final next(); false without error asks for more bytes.

Effects: fail.

### `CsvReader.position`

```gizlang
function CsvReader.position(self: CsvReader): i64
```

Bytes consumed through the last complete record, for bounded input-window retention.

### `CsvReader.count`

```gizlang
function CsvReader.count(self: CsvReader): i64
```

The number of fields in the current record.

### `CsvReader.field`

```gizlang
function CsvReader.field(self: CsvReader, index: i64): Option<Field>
```

The field `index` of the current record, if it exists.

Effects: fail.

### `CsvReader.text`

```gizlang
function CsvReader.text(self: CsvReader, index: i64): string throws CsvError
```

Only this operation copies/unescapes a field. Binary fields remain usable
as ranges; invalid UTF-8 or an invalid index is a Result, never a fault.

Effects: fail.

### `CsvReader.number`

```gizlang
function CsvReader.number(self: CsvReader, index: i64): Option<f64>
```

Whole-field decimal syntax, as Text.parseF64, validated in place. Empty,
escaped, non-numeric and missing fields return none, without changing error.

Effects: fail.

### `CsvReader.integer`

```gizlang
function CsvReader.integer(self: CsvReader, index: i64): Option<i64>
```

Exact i64, accumulating negatively so MIN is representable; no string.

Effects: fail.

### `CsvWriter.format`

```gizlang
function CsvWriter.format(self: mut CsvWriter, delimiter: u64, quote: u64): bool
```

Set the delimiter and the quote byte; false if they are not valid.

Effects: fail.

### `CsvWriter.error`

```gizlang
function CsvWriter.error(self: CsvWriter): Option<CsvError>
```

The error that stopped the writer, if there is one.

### `CsvWriter.field`

```gizlang
function CsvWriter.field(self: mut CsvWriter, value: bytes): void
```

Write one field of the current record, quoted when it needs it.

Effects: fail.

### `CsvWriter.end`

```gizlang
function CsvWriter.end(self: mut CsvWriter): void
```

End the current record.

Effects: fail.

### `CsvWriter.data`

```gizlang
function CsvWriter.data(self: CsvWriter): bytes
```

The CSV text written so far.

