///|
pub struct ArrayRef {
priv doc : Doc
priv name : Parent
}
///|
pub fn Doc::get_or_insert_array(self : Doc, name : String) -> ArrayRef {
let name : Parent = Root(name)
self.register_kind(name, SharedArray)
{ doc: self, name, }
}
///|
pub fn ArrayRef::length(self : ArrayRef) -> Int32 {
let sequence : Text = { doc: self.doc, name: self.name, }
sequence.length()
}
///|
pub fn ArrayRef::to_array(self : ArrayRef) -> Array[Out] {
let result : Array[Out] = []
let mut cursor = self.doc.branch(self.name).head
while cursor is Some(id) {
let item = self.doc.items[id]
if !item.deleted {
match item.content {
Values(values) =>
for value in values {
result.push(Value(value))
}
LegacyJson(values) =>
for value in values {
result.push(Value(value))
}
Binary(b) => result.push(Value(Buffer(b)))
Embed(value) => result.push(Value(value))
Shared(kind) => result.push(self.doc.shared_output(item.id, kind))
Subdocument(child) => result.push(Subdoc(child))
_ => ()
}
}
cursor = item.right
}
result
}
///|
fn Doc::insert_content(
self : Doc,
name : Parent,
key : String?,
left : Id?,
right : Id?,
content : Content,
) -> Id {
self.with_mutation(fn() {
let length = content.length()
guard length > 0 else { abort("empty item") }
let clock = self.next_clock(self.client)
guard clock.to_uint64() + length.to_uint64() <= 0xffff_ffffUL else {
abort("document clock exhausted")
}
let origin = left.map(fn(id) {
let item = self.items[id]
(
{
client: id.client,
clock: id.clock + item.content.length().reinterpret_as_uint() - 1U,
} : Id)
})
let raw : RawItem = {
id: { client: self.client, clock, },
origin,
right_origin: right,
parent: Some(name),
parent_sub: key,
content,
}
guard self.integrate(raw) else {
abort("local insert has missing dependency")
}
self.settle()
raw.id
})
}
///|
pub fn ArrayRef::insert_range(
self : ArrayRef,
index : Int32,
values : Array[Any],
) -> Unit {
let sequence : Text = { doc: self.doc, name: self.name, }
let (left, right) = sequence.position(index)
if values.is_empty() {
return
}
self.doc.insert_content(
self.name,
None,
left,
right,
Values(ReadOnlyArray::from_array(values[:])),
)
|> ignore
}
///|
pub fn ArrayRef::remove_range(
self : ArrayRef,
index : Int32,
length : Int32,
) -> Unit {
let sequence : Text = { doc: self.doc, name: self.name, }
sequence.remove_range(index, length)
}
///|
pub struct MapRef {
priv doc : Doc
priv name : Parent
}
///|
pub fn Doc::get_or_insert_map(self : Doc, name : String) -> MapRef {
let name : Parent = Root(name)
self.register_kind(name, SharedMap)
{ doc: self, name, }
}
///|
pub fn MapRef::insert(self : MapRef, key : String, value : Any) -> Unit {
self.doc.insert_content(
self.name,
Some(key),
self.doc.branch(self.name).values.get(key),
None,
Values([value]),
)
|> ignore
}
///|
pub fn MapRef::get(self : MapRef, key : String) -> Out? {
guard self.doc.branch(self.name).values.get(key) is Some(id) else {
return None
}
let item = self.doc.items[id]
if item.deleted {
return None
}
match item.content {
Values(values) => Some(Value(values[values.length() - 1]))
LegacyJson(values) => Some(Value(values[values.length() - 1]))
Binary(b) => Some(Value(Buffer(b)))
Embed(value) => Some(Value(value))
Shared(kind) => Some(self.doc.shared_output(item.id, kind))
Subdocument(child) => Some(Subdoc(child))
_ => None
}
}
///|
pub fn MapRef::remove(self : MapRef, key : String) -> Unit {
self.doc.with_mutation(fn() {
if self.doc.branch(self.name).values.get(key) is Some(id) {
self.doc.mark_deleted(self.doc.items[id])
}
})
}
///|
pub fn MapRef::entries(self : MapRef) -> Array[(String, Out)] {
let entries = []
for key, _ in self.doc.branch(self.name).values {
if self.get(key) is Some(value) {
entries.push((key, value))
}
}
entries.sort_by(fn(a, b) { a.0.compare(b.0) })
entries
}