This also provides ensurance through zig build test that all fields are documented in markdown so they do not get out of sync
59 lines
3.1 KiB
Zig
59 lines
3.1 KiB
Zig
//! SRF coercion policy, in one place.
|
|
//!
|
|
//! SRF encodes a field's type in its separator: `key::v` is a string,
|
|
//! `key:num:v` a number, `key:bool:v` a boolean. Coercion into a typed
|
|
//! struct therefore depends on the writer having picked the right one.
|
|
//!
|
|
//! That assumption holds for files zfin writes and breaks for files
|
|
//! people write, so the two get different options - and which one a
|
|
//! parser wants is a property of where the file came from, not of the
|
|
//! struct being parsed. Naming the two policies keeps that decision
|
|
//! visible at the call site instead of buried in whichever comment
|
|
//! happened to explain it first.
|
|
|
|
const srf = @import("srf");
|
|
|
|
/// For files a HUMAN edits: `portfolio.srf`, `accounts.srf`,
|
|
/// `metadata.srf`, `watchlist.srf`, `transaction_log.srf`,
|
|
/// `projections.srf`, `imported_values.srf`, `acknowledgments.srf`, and
|
|
/// the keybind config.
|
|
///
|
|
/// **`grep -rn srf_opts.user_edited src/` is the authoritative index of
|
|
/// hand-edited SRF files, and `src/srf_lint.zig`'s `schemas` registry
|
|
/// must cover the same set.** A new parse site here needs a matching
|
|
/// `srf_schema` on its model and an entry in that registry, or the
|
|
/// file's field names go unchecked - SRF silently discards a key that
|
|
/// names no field of the target struct, so a typo in an unregistered
|
|
/// file is invisible. (The one deliberate exception is
|
|
/// `imported_values.srf`, which is machine-generated; see the registry's
|
|
/// doc comment.) Zig cannot enforce this - there is no way to ask which
|
|
/// files reference a constant - so it is a convention, hence this note.
|
|
///
|
|
/// Accepts a string where a number was declared, because a hand-typed
|
|
/// `close_price::200.00` instead of `close_price:num:200.00` is a
|
|
/// slip, not a different intent. SRF's own doc says as much: strict
|
|
/// coercion is "intended for performant access for cache use cases...
|
|
/// if you want to use this for human-edited files, turn this on".
|
|
///
|
|
/// It is also a safety measure, which is the part worth not
|
|
/// forgetting. Under strict coercion a string reaching a numeric field
|
|
/// falls through to an unchecked `val.?.number` inside SRF - a panic
|
|
/// in Debug/ReleaseSafe and undefined behaviour in ReleaseFast, which
|
|
/// is how zfin is built. One `close_price::200.00` once took down
|
|
/// every `zfin portfolio` run; the fix was to turn this on for
|
|
/// `portfolio.srf` alone, which left every other hand-edited file
|
|
/// exposed to the same typo.
|
|
pub const user_edited: srf.CoercionOptions = .{ .strings_to_numbers = true };
|
|
|
|
/// For files ZFIN writes: the candle, quote, and options caches,
|
|
/// `cusip_tickers.srf` under `cache_dir`, server responses, and the
|
|
/// `history/<date>-portfolio.srf` snapshots produced by
|
|
/// `zfin snapshot`.
|
|
///
|
|
/// Keeps SRF's strict default. The writer is a machine that always
|
|
/// emits `:num:` for numbers, so accepting a string instead would only
|
|
/// mask a serializer bug rather than tolerate a human slip - these
|
|
/// files are not edited after the fact. Strictness is also free
|
|
/// performance on the hot paths, where a cached candle file is
|
|
/// millions of records.
|
|
pub const machine_written: srf.CoercionOptions = .{};
|