//! 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/-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 = .{};