Compare commits
No commits in common. "f4facdb700101a150952922faa254f0f0d3e3677" and "e45a5ffe34182304a4f01899098487a1ee401b87" have entirely different histories.
f4facdb700
...
e45a5ffe34
2 changed files with 0 additions and 99 deletions
89
README.md
89
README.md
|
|
@ -155,95 +155,6 @@ Fields follow the format `key:type_hint:value`:
|
||||||
| Binary | `binary` | `data:binary:base64...` |
|
| Binary | `binary` | `data:binary:base64...` |
|
||||||
| Length-prefixed string | *(byte count)* | `bio:12:hello\nworld!` |
|
| Length-prefixed string | *(byte count)* | `bio:12:hello\nworld!` |
|
||||||
|
|
||||||
## Directives
|
|
||||||
|
|
||||||
Directives are parser instructions that appear at the top of an SRF file. They
|
|
||||||
use the `#!` prefix and must appear before any data records (except `#!eof`,
|
|
||||||
which marks the end of data). Inline comments are allowed after directives.
|
|
||||||
Unrecognized directives are silently ignored for forward compatibility.
|
|
||||||
|
|
||||||
| Directive | Parameters | Description |
|
|
||||||
|----------------------------|------------------|------------------------------------------------------|
|
|
||||||
| `#!srfv1` | none | Magic header identifying the file as SRF version 1 |
|
|
||||||
| `#!long` | none | Select long format (newline-delimited fields) |
|
|
||||||
| `#!compact` | none | Select compact format (comma-delimited fields) |
|
|
||||||
| `#!requireeof` | none | Require `#!eof` marker or parsing fails |
|
|
||||||
| `#!eof` | none | End-of-file marker for corruption detection |
|
|
||||||
| `#!expires=<unix_ts>` | `i64` timestamp | Cache expiration time (checked via `isFresh()`) |
|
|
||||||
| `#!created=<unix_ts>` | `i64` timestamp | Data creation timestamp (metadata only) |
|
|
||||||
| `#!modified=<unix_ts>` | `i64` timestamp | Data modification timestamp (metadata only) |
|
|
||||||
|
|
||||||
### `#!srfv1`
|
|
||||||
|
|
||||||
Mandatory magic header that must appear on the very first line of every SRF
|
|
||||||
file. Identifies the file format and version. A missing header causes a parse
|
|
||||||
error; duplicates are also rejected.
|
|
||||||
|
|
||||||
### `#!long`
|
|
||||||
|
|
||||||
Selects long format mode where fields are delimited by newlines and records are
|
|
||||||
separated by blank lines. Suitable for hand-edited configuration files. Mutually
|
|
||||||
exclusive with `#!compact`.
|
|
||||||
|
|
||||||
### `#!compact`
|
|
||||||
|
|
||||||
Selects compact format mode where fields are delimited by commas and records are
|
|
||||||
separated by newlines. This is the default format, so the directive is optional.
|
|
||||||
Designed for machine generation where space efficiency matters.
|
|
||||||
|
|
||||||
### `#!requireeof`
|
|
||||||
|
|
||||||
When present, parsing will fail if the `#!eof` marker is not found at the end of
|
|
||||||
the file. This is a corruption detection mechanism to ensure the file was not
|
|
||||||
truncated during a write.
|
|
||||||
|
|
||||||
### `#!eof`
|
|
||||||
|
|
||||||
Marks the end of SRF data. Any data appearing after this directive causes a
|
|
||||||
parse error. Can appear in the header (indicating an empty file) or after data
|
|
||||||
records. Paired with `#!requireeof` for corruption detection.
|
|
||||||
|
|
||||||
### `#!expires=<unix_timestamp>`
|
|
||||||
|
|
||||||
Sets a cache expiration timestamp. The value is a Unix timestamp (seconds since
|
|
||||||
epoch) as an `i64`. The `RecordIterator.isFresh()` method checks this against
|
|
||||||
the current time. Data is always returned regardless of freshness -- callers
|
|
||||||
decide whether to use stale data.
|
|
||||||
|
|
||||||
```
|
|
||||||
#!srfv1
|
|
||||||
#!expires=1772589213
|
|
||||||
key::cached_value
|
|
||||||
```
|
|
||||||
|
|
||||||
### `#!created=<unix_timestamp>`
|
|
||||||
|
|
||||||
Records when the data was created. The value is a Unix timestamp as an `i64`.
|
|
||||||
This is metadata only -- the library tracks it but takes no action on it.
|
|
||||||
Available on the iterator/parsed result immediately after construction.
|
|
||||||
|
|
||||||
### `#!modified=<unix_timestamp>`
|
|
||||||
|
|
||||||
Records when the data was last modified. The value is a Unix timestamp as an
|
|
||||||
`i64`. Like `#!created`, this is metadata only and is available on the
|
|
||||||
iterator/parsed result after construction.
|
|
||||||
|
|
||||||
### Example with multiple directives
|
|
||||||
|
|
||||||
```
|
|
||||||
#!srfv1
|
|
||||||
#!requireeof
|
|
||||||
#!long
|
|
||||||
#!expires=1772589213
|
|
||||||
#!created=1772500000
|
|
||||||
name::alice
|
|
||||||
age:num:30
|
|
||||||
|
|
||||||
name::bob
|
|
||||||
age:num:25
|
|
||||||
#!eof
|
|
||||||
```
|
|
||||||
|
|
||||||
## Implementation Concerns
|
## Implementation Concerns
|
||||||
|
|
||||||
**Parser robustness:**
|
**Parser robustness:**
|
||||||
|
|
|
||||||
10
src/srf.zig
10
src/srf.zig
|
|
@ -1059,12 +1059,6 @@ pub const FormatOptions = struct {
|
||||||
/// Specify an expiration time for the data being written
|
/// Specify an expiration time for the data being written
|
||||||
expires: ?i64 = null,
|
expires: ?i64 = null,
|
||||||
|
|
||||||
/// Specify a created time for the data being written
|
|
||||||
created: ?i64 = null,
|
|
||||||
|
|
||||||
/// Specify a modified time for the data being written
|
|
||||||
modified: ?i64 = null,
|
|
||||||
|
|
||||||
/// By setting this to false, you can avoid writing any header/footer data
|
/// By setting this to false, you can avoid writing any header/footer data
|
||||||
/// and just format the record. This is useful for appending to an existing
|
/// and just format the record. This is useful for appending to an existing
|
||||||
/// srf file rather than overwriting all the data
|
/// srf file rather than overwriting all the data
|
||||||
|
|
@ -1137,10 +1131,6 @@ fn frontMatter(writer: *std.Io.Writer, options: FormatOptions) !void {
|
||||||
try writer.writeAll("#!requireeof\n");
|
try writer.writeAll("#!requireeof\n");
|
||||||
if (options.expires) |e|
|
if (options.expires) |e|
|
||||||
try writer.print("#!expires={d}\n", .{e});
|
try writer.print("#!expires={d}\n", .{e});
|
||||||
if (options.created) |e|
|
|
||||||
try writer.print("#!created={d}\n", .{e});
|
|
||||||
if (options.modified) |e|
|
|
||||||
try writer.print("#!modified={d}\n", .{e});
|
|
||||||
}
|
}
|
||||||
fn epilogue(writer: *std.Io.Writer, options: FormatOptions) !void {
|
fn epilogue(writer: *std.Io.Writer, options: FormatOptions) !void {
|
||||||
if (!options.emit_directives) return;
|
if (!options.emit_directives) return;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue