Skip to content

non finite float

Tags: codec, json, sqlite, choosing an engine

Features: redb, sqlite, json, toml, ron

What a float that is not a number does to a store.

NaN and the infinities are ordinary f64 values a GUI produces by dividing badly. Three of the five engines carry them: msgpack writes the IEEE bits, and TOML and RON have nan and inf in their grammars.

JSON has no spelling for either, and neither serde_json nor sonic_rs says so - both write null, which then fails to read back as a float. That costs two engines rather than one, because sqlite stores its values as JSON and nothing in its name says which format that is.

So which engines have it follows the codec rather than the file extension, and the two are not the pair anyone guesses. A store whose codec cannot read the value back refuses the write instead of taking it: left alone it lands as null, set answers Ok, and the field goes on reporting the number it held before while the file holds nothing of the sort.

limits(|l| l.portable_across(..)) extends the refusal to engines that are not running. A store on redb that promises to stay readable on json refuses what msgpack alone would have held.

let readings = Readings::new_with(&store).unwrap();
readings.ratio().set(1.5).unwrap();
let written = readings.ratio().set(f64::NAN);
let after = readings.ratio().get();
let written = readings.ratio().set(f64::NAN);
taken, and the field holds NaN

what the field holds afterwards reads back NaN.

let written = readings.ratio().set(f64::NAN);
what was written to nonfinite.ratio will not encode

what the field holds afterwards reads back 1.5.

let written = readings.ratio().set(f64::NAN);
what was written to nonfinite.ratio will not encode

what the field holds afterwards reads back 1.5.

let written = readings.ratio().set(f64::NAN);
taken, and the field holds NaN

what the field holds afterwards reads back NaN.

let written = readings.ratio().set(f64::NAN);
taken, and the field holds NaN

what the field holds afterwards reads back NaN.