aboutsummaryrefslogtreecommitdiffstats
path: root/src/document/store.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/document/store.rs')
-rw-r--r--src/document/store.rs31
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