more type fixes and rethinking writeStructs

This commit is contained in:
Kevin Jahns
2019-04-02 23:08:58 +02:00
parent 73c28952c2
commit e23582b1cd
35 changed files with 952 additions and 695 deletions

View File

@@ -2,7 +2,7 @@
* @module structs
*/
import { readID, createID, writeID, writeNullID, ID } from '../utils/ID.js' // eslint-disable-line
import { readID, createID, writeID, ID } from '../utils/ID.js' // eslint-disable-line
import { GC } from './GC.js'
import * as encoding from 'lib0/encoding.js'
import * as decoding from 'lib0/decoding.js'
@@ -16,6 +16,7 @@ import * as binary from 'lib0/binary.js'
import { AbstractRef, AbstractStruct } from './AbstractStruct.js' // eslint-disable-line
import * as error from 'lib0/error.js'
import { replaceStruct, addStruct } from '../utils/StructStore.js'
import { addToDeleteSet } from '../utils/DeleteSet.js'
/**
* Split leftItem into two items
@@ -51,13 +52,7 @@ export const splitItem = (transaction, leftItem, diff) => {
foundOrigins.add(o)
o = o.right
}
const right = leftItem.splitAt(transaction, diff)
if (transaction.added.has(leftItem)) {
transaction.added.add(right)
} else if (transaction.deleted.has(leftItem)) {
transaction.deleted.add(right)
}
return rightItem
return leftItem.splitAt(transaction, diff)
}
/**
@@ -230,7 +225,6 @@ export class AbstractItem extends AbstractStruct {
if (parent !== null) {
maplib.setIfUndefined(transaction.changed, parent, set.create).add(parentSub)
}
transaction.added.add(this)
// @ts-ignore
if (parent._item.deleted || (left !== null && parentSub !== null)) {
// delete if parent is deleted or if this is not the current attribute value of parent
@@ -341,15 +335,11 @@ export class AbstractItem extends AbstractStruct {
/**
* Computes the last content address of this Item.
*
* TODO: do still need this?
* @private
*/
get lastId () {
/**
* @type {any}
*/
const id = this.id
return createID(id.user, id.clock + this.length - 1)
return createID(this.id.client, this.id.clock + this.length - 1)
}
/**
@@ -406,8 +396,8 @@ export class AbstractItem extends AbstractStruct {
parent._length -= this.length
}
this.deleted = true
addToDeleteSet(transaction.deleteSet, this.id, this.length)
maplib.setIfUndefined(transaction.changed, parent, set.create).add(this.parentSub)
transaction.deleted.add(this)
}
}
@@ -437,18 +427,26 @@ export class AbstractItem extends AbstractStruct {
* This is called when this Item is sent to a remote peer.
*
* @param {encoding.Encoder} encoder The encoder to write data to.
* @param {number} offset
* @param {number} encodingRef
* @private
*/
write (encoder, encodingRef) {
write (encoder, offset, encodingRef) {
const info = (encodingRef & binary.BITS5) |
((this.origin === null) ? 0 : binary.BIT8) | // origin is defined
((this.rightOrigin === null) ? 0 : binary.BIT7) | // right origin is defined
((this.parentSub !== null) ? 0 : binary.BIT6) // parentSub is non-null
encoding.writeUint8(encoder, info)
writeID(encoder, this.id)
if (this.origin !== null) {
writeID(encoder, this.origin.lastId)
if (offset === 0) {
writeID(encoder, this.id)
if (this.origin !== null) {
writeID(encoder, this.origin.lastId)
}
} else {
writeID(encoder, createID(this.id.client, this.id.clock + offset))
if (this.origin !== null) {
writeID(encoder, createID(this.id.client, this.id.clock + offset - 1))
}
}
if (this.rightOrigin !== null) {
writeID(encoder, this.rightOrigin.id)
@@ -470,10 +468,10 @@ export class AbstractItem extends AbstractStruct {
if (ykey === null) {
throw error.unexpectedCase()
}
writeNullID(encoder)
encoding.writeVarUint(encoder, 1) // write parentYKey
encoding.writeVarString(encoder, ykey)
} else {
// neither origin nor right is defined
encoding.writeVarUint(encoder, 0) // write parent id
// @ts-ignore _item is defined because parent is integrated
writeID(encoder, parent._item.id)
}
@@ -487,19 +485,11 @@ export class AbstractItem extends AbstractStruct {
export class AbstractItemRef extends AbstractRef {
/**
* @param {decoding.Decoder} decoder
* @param {ID} id
* @param {number} info
*/
constructor (decoder, info) {
super()
const id = readID(decoder)
if (id === null) {
throw error.unexpectedCase()
}
/**
* The uniqe identifier of this type.
* @type {ID}
*/
this.id = id
constructor (decoder, id, info) {
super(id)
/**
* The item that was originally to the left of this item.
* @type {ID | null}
@@ -511,18 +501,19 @@ export class AbstractItemRef extends AbstractRef {
*/
this.right = (info & binary.BIT7) === binary.BIT7 ? readID(decoder) : null
const canCopyParentInfo = (info & (binary.BIT7 | binary.BIT8)) === 0
/**
* The parent type.
* @type {ID | null}
*/
this.parent = canCopyParentInfo ? readID(decoder) : null
const hasParentYKey = decoding.readVarUint(decoder) === 1
/**
* If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
* and we read the next string as parentYKey.
* It indicates how we store/retrieve parent from `y.share`
* @type {string|null}
*/
this.parentYKey = canCopyParentInfo && this.parent === null ? decoding.readVarString(decoder) : null
this.parentYKey = canCopyParentInfo && hasParentYKey ? decoding.readVarString(decoder) : null
/**
* The parent type.
* @type {ID | null}
*/
this.parent = canCopyParentInfo && !hasParentYKey ? readID(decoder) : null
/**
* If the parent refers to this item with some kind of key (e.g. YMap, the
* key is specified here. The key is then used to refer to the list in which
@@ -531,11 +522,22 @@ export class AbstractItemRef extends AbstractRef {
* @type {String | null}
*/
this.parentSub = canCopyParentInfo && (info & binary.BIT6) === binary.BIT6 ? decoding.readVarString(decoder) : null
const missing = this._missing
if (this.left !== null) {
missing.push(this.left)
}
if (this.right !== null) {
missing.push(this.right)
}
if (this.parent !== null) {
missing.push(this.parent)
}
}
/**
* @param {Transaction} transaction
* @return {Array<ID|null>}
*/
getMissing () {
getMissing (transaction) {
return [
createID(this.id.client, this.id.clock - 1),
this.left,

View File

@@ -23,22 +23,50 @@ export class AbstractStruct {
get length () {
throw error.methodUnimplemented()
}
/**
* @type {boolean}
*/
get deleted () {
throw error.methodUnimplemented()
}
/**
* @param {encoding.Encoder} encoder The encoder to write data to.
* @param {number} offset
* @param {number} encodingRef
* @private
*/
write (encoder, encodingRef) {
write (encoder, offset, encodingRef) {
throw error.methodUnimplemented()
}
/**
* @param {Transaction} transaction
*/
integrate (transaction) {
throw error.methodUnimplemented()
}
}
export class AbstractRef {
/**
* @param {ID} id
*/
constructor (id) {
/**
* @type {Array<ID>}
*/
this._missing = []
/**
* The uniqe identifier of this type.
* @type {ID}
*/
this.id = id
}
/**
* @param {Transaction} transaction
* @return {Array<ID|null>}
*/
getMissing () {
return []
getMissing (transaction) {
return this._missing
}
/**
* @param {Transaction} transaction

View File

@@ -28,10 +28,15 @@ export class GC extends AbstractStruct {
/**
* @param {encoding.Encoder} encoder
* @param {number} offset
*/
write (encoder) {
write (encoder, offset) {
encoding.writeUint8(encoder, structGCRefNumber)
writeID(encoder, this.id)
if (offset === 0) {
writeID(encoder, this.id)
} else {
writeID(encoder, createID(this.id.client, this.id.clock + offset))
}
encoding.writeVarUint(encoder, this.length)
}
}
@@ -39,14 +44,11 @@ export class GC extends AbstractStruct {
export class GCRef extends AbstractRef {
/**
* @param {decoding.Decoder} decoder
* @param {ID} id
* @param {number} info
*/
constructor (decoder, info) {
super()
const id = readID(decoder)
if (id === null) {
throw new Error('expected id')
}
constructor (decoder, id, info) {
super(id)
/**
* @type {ID}
*/

View File

@@ -43,9 +43,10 @@ export class ItemBinary extends AbstractItem {
}
/**
* @param {encoding.Encoder} encoder
* @param {number} offset
*/
write (encoder) {
super.write(encoder, structBinaryRefNumber)
write (encoder, offset) {
super.write(encoder, offset, structBinaryRefNumber)
encoding.writePayload(encoder, this.content)
}
}
@@ -53,10 +54,11 @@ export class ItemBinary extends AbstractItem {
export class ItemBinaryRef extends AbstractItemRef {
/**
* @param {decoding.Decoder} decoder
* @param {ID} id
* @param {number} info
*/
constructor (decoder, info) {
super(decoder, info)
constructor (decoder, id, info) {
super(decoder, id, info)
/**
* @type {ArrayBuffer}
*/

View File

@@ -8,9 +8,9 @@ import { AbstractItem, AbstractItemRef } from './AbstractItem.js'
import * as encoding from 'lib0/encoding.js'
import * as decoding from 'lib0/decoding.js'
import { ID } from '../utils/ID.js' // eslint-disable-line
import { ItemType } from './ItemType.js' // eslint-disable-line
import { Y } from '../utils/Y.js' // eslint-disable-line
import { getItemCleanEnd, getItemCleanStart, getItemType } from '../utils/StructStore.js'
import { AbstractType } from '../types/AbstractType.js' // eslint-disable-line
import { Transaction } from '../utils/Transaction.js' // eslint-disable-line
export const structDeletedRefNumber = 2
@@ -39,20 +39,22 @@ export class ItemDeleted extends AbstractItem {
}
/**
* @param {encoding.Encoder} encoder
* @param {number} offset
*/
write (encoder) {
super.write(encoder, structDeletedRefNumber)
encoding.writeVarUint(encoder, this.length)
write (encoder, offset) {
super.write(encoder, offset, structDeletedRefNumber)
encoding.writeVarUint(encoder, this.length - offset)
}
}
export class ItemDeletedRef extends AbstractItemRef {
/**
* @param {decoding.Decoder} decoder
* @param {ID} id
* @param {number} info
*/
constructor (decoder, info) {
super(decoder, info)
constructor (decoder, id, info) {
super(decoder, id, info)
/**
* @type {number}
*/

View File

@@ -39,9 +39,10 @@ export class ItemEmbed extends AbstractItem {
}
/**
* @param {encoding.Encoder} encoder
* @param {number} offset
*/
write (encoder) {
super.write(encoder, structEmbedRefNumber)
write (encoder, offset) {
super.write(encoder, offset, structEmbedRefNumber)
encoding.writeVarString(encoder, JSON.stringify(this.embed))
}
}
@@ -49,10 +50,11 @@ export class ItemEmbed extends AbstractItem {
export class ItemEmbedRef extends AbstractItemRef {
/**
* @param {decoding.Decoder} decoder
* @param {ID} id
* @param {number} info
*/
constructor (decoder, info) {
super(decoder, info)
constructor (decoder, id, info) {
super(decoder, id, info)
/**
* @type {ArrayBuffer}
*/

View File

@@ -44,9 +44,10 @@ export class ItemFormat extends AbstractItem {
}
/**
* @param {encoding.Encoder} encoder
* @param {number} offset
*/
write (encoder) {
super.write(encoder, structFormatRefNumber)
write (encoder, offset) {
super.write(encoder, offset, structFormatRefNumber)
encoding.writeVarString(encoder, this.key)
encoding.writeVarString(encoder, JSON.stringify(this.value))
}
@@ -55,10 +56,11 @@ export class ItemFormat extends AbstractItem {
export class ItemFormatRef extends AbstractItemRef {
/**
* @param {decoding.Decoder} decoder
* @param {ID} id
* @param {number} info
*/
constructor (decoder, info) {
super(decoder, info)
constructor (decoder, id, info) {
super(decoder, id, info)
/**
* @type {string}
*/

View File

@@ -58,9 +58,10 @@ export class ItemJSON extends AbstractItem {
}
/**
* @param {encoding.Encoder} encoder
* @param {number} offset
*/
write (encoder) {
super.write(encoder, structJSONRefNumber)
write (encoder, offset) {
super.write(encoder, offset, structJSONRefNumber)
const len = this.content.length
encoding.writeVarUint(encoder, len)
for (let i = 0; i < len; i++) {
@@ -73,10 +74,11 @@ export class ItemJSON extends AbstractItem {
export class ItemJSONRef extends AbstractItemRef {
/**
* @param {decoding.Decoder} decoder
* @param {ID} id
* @param {number} info
*/
constructor (decoder, info) {
super(decoder, info)
constructor (decoder, id, info) {
super(decoder, id, info)
const len = decoding.readVarUint(decoder)
const cs = []
for (let i = 0; i < len; i++) {

View File

@@ -62,9 +62,10 @@ export class ItemString extends AbstractItem {
}
/**
* @param {encoding.Encoder} encoder
* @param {number} offset
*/
write (encoder) {
super.write(encoder, structStringRefNumber)
write (encoder, offset) {
super.write(encoder, offset, structStringRefNumber)
encoding.writeVarString(encoder, this.string)
}
}
@@ -72,10 +73,11 @@ export class ItemString extends AbstractItem {
export class ItemStringRef extends AbstractItemRef {
/**
* @param {decoding.Decoder} decoder
* @param {ID} id
* @param {number} info
*/
constructor (decoder, info) {
super(decoder, info)
constructor (decoder, id, info) {
super(decoder, id, info)
/**
* @type {string}
*/

View File

@@ -73,37 +73,41 @@ export class ItemType extends AbstractItem {
return new ItemType(id, left, right, parent, parentSub, this.type._copy())
}
/**
* @param {encoding.Encoder} encoder
* @param {Transaction} transaction
*/
write (encoder) {
super.write(encoder, structTypeRefNumber)
integrate (transaction) {
this.type._integrate(transaction, this)
}
/**
* @param {encoding.Encoder} encoder
* @param {number} offset
*/
write (encoder, offset) {
super.write(encoder, offset, structTypeRefNumber)
this.type._write(encoder)
}
/**
* Mark this Item as deleted.
*
* @param {Transaction} transaction The Yjs instance
* @param {boolean} createDelete Whether to propagate a message that this
* Type was deleted.
* @param {boolean} [gcChildren=(y._hasUndoManager===false)] Whether to garbage
* collect the children of this type.
* @private
*/
delete (transaction, createDelete, gcChildren = transaction.y.gcEnabled) {
delete (transaction) {
const y = transaction.y
super.delete(transaction, createDelete, gcChildren)
super.delete(transaction)
transaction.changed.delete(this.type)
transaction.changedParentTypes.delete(this.type)
// delete map types
for (let value of this.type._map.values()) {
if (!value.deleted) {
value.delete(transaction, false, gcChildren)
value.delete(transaction)
}
}
// delete array types
let t = this.type._start
while (t !== null) {
if (!t.deleted) {
t.delete(transaction, false, gcChildren)
t.delete(transaction)
}
t = t.right
}
@@ -133,13 +137,14 @@ export class ItemType extends AbstractItem {
}
}
export class ItemBinaryRef extends AbstractItemRef {
export class ItemTypeRef extends AbstractItemRef {
/**
* @param {decoding.Decoder} decoder
* @param {ID} id
* @param {number} info
*/
constructor (decoder, info) {
super(decoder, info)
constructor (decoder, id, info) {
super(decoder, id, info)
const typeRef = decoding.readVarUint(decoder)
/**
* @type {AbstractType}