public static IDictionary <int, List <AbstractStruct> > ReadClientStructRefs(IUpdateDecoder decoder, YDoc doc) { var clientRefs = new Dictionary <int, List <AbstractStruct> >(); var numOfStateUpdates = decoder.Reader.ReadVarUint(); for (int i = 0; i < numOfStateUpdates; i++) { var numberOfStructs = (int)decoder.Reader.ReadVarUint(); Debug.Assert(numberOfStructs >= 0); var refs = new List <AbstractStruct>(numberOfStructs); var client = decoder.ReadClient(); var clock = (int)decoder.Reader.ReadVarUint(); clientRefs[client] = refs; for (int j = 0; j < numberOfStructs; j++) { var info = decoder.ReadInfo(); if ((Bits.Bits5 & info) != 0) { // The item that was originally to the left of this item. var leftOrigin = (info & Bit.Bit8) == Bit.Bit8 ? (ID?)decoder.ReadLeftId() : null; // The item that was originally to the right of this item. var rightOrigin = (info & Bit.Bit7) == Bit.Bit7 ? (ID?)decoder.ReadRightId() : null; var cantCopyParentInfo = (info & (Bit.Bit7 | Bit.Bit8)) == 0; var hasParentYKey = cantCopyParentInfo ? decoder.ReadParentInfo() : false; // 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'. var parentYKey = cantCopyParentInfo && hasParentYKey?decoder.ReadString() : null; var str = new Item( new ID(client, clock), null, // left leftOrigin, null, // right rightOrigin, // rightOrigin cantCopyParentInfo && !hasParentYKey ? decoder.ReadLeftId() : (parentYKey != null ? (object)doc.Get <AbstractType>(parentYKey) : null), // parent cantCopyParentInfo && (info & Bit.Bit6) == Bit.Bit6 ? decoder.ReadString() : null, // parentSub ReadItemContent(decoder, info) // content ); refs.Add(str); clock += str.Length; } else { var length = decoder.ReadLength(); refs.Add(new GC(new ID(client, clock), length)); clock += length; } } } return(clientRefs); }
public static AbsolutePosition TryCreateFromAbsolutePosition(RelativePosition rpos, YDoc doc) { var store = doc.Store; var rightId = rpos.Item; var typeId = rpos.TypeId; var tName = rpos.TName; int index = 0; AbstractType type; if (rightId != null) { if (store.GetState(rightId.Value.Client) <= rightId.Value.Clock) { return(null); } var res = store.FollowRedone(rightId.Value); var right = res.item as Item; if (right == null) { return(null); } type = right.Parent as AbstractType; Debug.Assert(type != null); if (type._item == null || !type._item.Deleted) { index = right.Deleted || !right.Countable ? 0 : res.diff; var n = right.Left as Item; while (n != null) { if (!n.Deleted && n.Countable) { index += n.Length; } n = n.Left as Item; } } } else { if (tName != null) { type = doc.Get <AbstractType>(tName); } else if (typeId != null) { if (store.GetState(typeId.Value.Client) <= typeId.Value.Clock) { // Type does not exist yet. return(null); } var item = store.FollowRedone(typeId.Value).item as Item; if (item != null && item.Content is ContentType) { type = (item.Content as ContentType).Type; } else { // Struct is garbage collected. return(null); } } else { throw new Exception(); } index = type.Length; } return(new AbsolutePosition(type, index)); }