diff options
| author | tv <tv@krebsco.de> | 2026-11-02 11:07:46 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-02 11:07:46 +0100 |
| commit | 8033c4dd17a637c21e1dd0c536edc04190851a21 (patch) | |
| tree | 34ac46ca8233fe32bd33b581f150e075d4fcd42d /src/document/store.rs | |
| parent | 2ad5d7c6ba0962e7ba2a8c919cddc1c2fa136f63 (diff) | |
api: drop $float as JSON number is OK
Diffstat (limited to 'src/document/store.rs')
| -rw-r--r-- | src/document/store.rs | 53 |
1 files changed, 37 insertions, 16 deletions
diff --git a/src/document/store.rs b/src/document/store.rs index 9075032..1a235b2 100644 --- a/src/document/store.rs +++ b/src/document/store.rs @@ -676,14 +676,27 @@ pub(crate) fn write_val_path( Ok(writing.retyped) } +/// Which values a write writes as the type of what they are written over (`stuck`). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) enum Sticky { + /// None: the value says its type (a type's own media type, a cast). + No, + /// A number without a fraction over a float: typed JSON says every other type + /// itself, but not a float's, as JSON numbers don't keep `2.0` apart from `2` in + /// every language. + Floats, + /// Plain JSON, which has fewer types than Automerge: where it is the JSON form of a + /// value of the type there (a string that reads as a timestamp, as base64, a number + /// without a fraction over a float, an unsigned integer or a counter, a string over + /// a text). + All, +} + /// How a write treats the types of what it writes over. pub(crate) struct Writing { - /// Types are sticky: the value comes as plain JSON, which has fewer types than - /// Automerge, and where it is the JSON form of a value of the type there (a string - /// that reads as a timestamp, as base64, a number without a fraction over a float, - /// an unsigned integer or a counter, a string over a text), it is written as that - /// type (`stuck`). Typed JSON and a type's own media type say the type themselves. - pub(crate) sticky: bool, + /// Types are sticky: what the value is written as where it is the JSON form of a + /// value of the type there. + pub(crate) sticky: Sticky, /// How sticky timestamps are written in JSON (`typed::TimestampFormat::json`). pub(crate) timestamps: TimestampFormat, /// Whether the write may change the type of what it writes over; if not, one that @@ -695,10 +708,10 @@ pub(crate) struct Writing { impl Writing { pub(crate) fn sticky(timestamps: TimestampFormat) -> Self { - Self::new(true, timestamps, true) + Self::new(Sticky::All, timestamps, true) } - pub(crate) fn new(sticky: bool, timestamps: TimestampFormat, retype: bool) -> Self { + pub(crate) fn new(sticky: Sticky, timestamps: TimestampFormat, retype: bool) -> Self { Self { sticky, timestamps, @@ -760,11 +773,23 @@ fn kind_of(held: &Value<'_>) -> Kind { } /// `value` written as the type of `held`, where it is a JSON form of a value of it -/// (`Writing::sticky`); None where it isn't (it is written as it is). -fn stuck(held: &Value<'_>, value: &Val, timestamps: TimestampFormat) -> Option<Val> { +/// as `sticky` says (`Writing::sticky`); None where it isn't (it is written as it is). +fn stuck( + held: &Value<'_>, + value: &Val, + sticky: Sticky, + timestamps: TimestampFormat, +) -> Option<Val> { let Val::Scalar(scalar) = value else { return None; }; + let over_float = matches!(held, Value::Scalar(held) if matches!(held.as_ref(), ScalarValue::F64(_))) + && matches!(scalar, ScalarValue::Int(_) | ScalarValue::Uint(_)); + match sticky { + Sticky::No => return None, + Sticky::Floats if !over_float => return None, + Sticky::Floats | Sticky::All => {} + } let held = match held { Value::Object(ObjType::Text) => { return match scalar { @@ -843,11 +868,7 @@ fn update_of<'v>( let Some((held, _)) = holds.first() else { return Ok((Update::Anew, Cow::Borrowed(value))); }; - let value = match writing - .sticky - .then(|| stuck(held, value, writing.timestamps)) - .flatten() - { + let value = match stuck(held, value, writing.sticky, writing.timestamps) { Some(stuck) => Cow::Owned(stuck), None => Cow::Borrowed(value), }; @@ -1083,7 +1104,7 @@ pub(crate) fn cast_path( .as_ref() .ok_or_else(|| not_castable(format!("{} is cast to nothing", held.kind.name())))?; let cast = typed::cast(held.kind, value, to, timestamps).map_err(not_castable)?; - write_val_path(doc, path, &cast, Writing::new(false, timestamps, true)) + write_val_path(doc, path, &cast, Writing::new(Sticky::No, timestamps, true)) } /// Inserts `value` into a list: `path` ends in the index it goes to (the items from |
