diff options
Diffstat (limited to 'src/document/store.rs')
| -rw-r--r-- | src/document/store.rs | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/src/document/store.rs b/src/document/store.rs index 07f2e1a..9075032 100644 --- a/src/document/store.rs +++ b/src/document/store.rs @@ -107,6 +107,9 @@ pub(crate) enum StoreError { /// wanted (`Writing::retype`). #[error("would change {0}")] Retyping(Retyped), + /// A cast that isn't possible (`cast_path`, `typed::cast`), and why. + #[error("can't cast {} to {}: {why}", .from.name(), .to.name())] + NotCastable { from: Kind, to: Kind, why: String }, /// A read at heads the document doesn't have (`at::At`). #[error("this node doesn't have these heads (yet)")] UnknownHeads, @@ -1055,6 +1058,34 @@ fn counter_at(doc: &impl ReadDoc, parent: &ObjId, prop: Prop) -> Result<i64, Sto } } +/// Casts what is at `path` (the newest of concurrent values, as a read resolves them) to +/// `to` (`typed::cast`, timestamps to and from strings in `timestamps`), written as a +/// write of the cast value would be (`write_val_path`); returns where that changed the +/// type. Already `to`: nothing changes. Nothing there: `NotFound`; no cast possible: +/// `NotCastable`. +pub(crate) fn cast_path( + doc: &mut impl Transactable, + path: &[String], + to: Kind, + timestamps: TimestampFormat, +) -> Result<Vec<Retyped>, StoreError> { + let held = read_held(doc, path)?.ok_or(StoreError::NotFound)?; + if held.kind == to { + return Ok(Vec::new()); + } + let not_castable = |why: String| StoreError::NotCastable { + from: held.kind, + to, + why, + }; + let value = held + .value + .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)) +} + /// Inserts `value` into a list: `path` ends in the index it goes to (the items from /// there on move up one; the list's length appends). An index past the end is /// `PastTheEnd`; a parent that isn't a list `NotAList`; anything but an index there, or |
