/// <summary> /// Update this <see cref="Schema" />'s EventHandlers /// </summary> /// <param name="previousInstance">The instance of an <see cref="IRef" /> from which we will copy the EventHandlers</param> public void MoveEventHandlers(IRef previousInstance) { OnChange = ((Schema)previousInstance).OnChange; OnRemove = ((Schema)previousInstance).OnRemove; foreach (KeyValuePair <int, string> item in ((Schema)previousInstance).fieldsByIndex) { object child = GetByIndex(item.Key); if (child is IRef) { ((IRef)child).MoveEventHandlers((IRef)previousInstance.GetByIndex(item.Key)); } } }
public void MoveEventHandlers(IRef previousInstance) { OnChange = ((Schema)previousInstance).OnChange; OnRemove = ((Schema)previousInstance).OnRemove; foreach (var item in ((Schema)previousInstance).fieldsByIndex) { var child = GetByIndex(item.Key); if (child is IRef) { ((IRef)child).MoveEventHandlers((IRef)previousInstance.GetByIndex(item.Key)); } } }
public void Decode(byte[] bytes, Iterator it = null, ReferenceTracker refs = null) { var decode = Decoder.GetInstance(); if (it == null) { it = new Iterator(); } if (refs == null) { refs = new ReferenceTracker(); } this.refs = refs; var totalBytes = bytes.Length; int refId = 0; IRef _ref = this; var changes = new List <DataChange>(); var allChanges = new OrderedDictionary(); // Dictionary<int, List<DataChange>> refs.Add(refId, this); while (it.Offset < totalBytes) { var _byte = bytes[it.Offset++]; if (_byte == (byte)SPEC.SWITCH_TO_STRUCTURE) { refId = Convert.ToInt32(decode.DecodeNumber(bytes, it)); _ref = refs.Get(refId); // // Trying to access a reference that haven't been decoded yet. // if (_ref == null) { throw new Exception("refId not found: " + refId); } // create empty list of changes for this refId. changes = new List <DataChange>(); allChanges[(object)refId] = changes; continue; } bool isSchema = _ref is Schema; var operation = (byte)((isSchema) ? (_byte >> 6) << 6 // "compressed" index + operation : _byte); // "uncompressed" index + operation (array/map items) if (operation == (byte)OPERATION.CLEAR) { ((ISchemaCollection)_ref).Clear(refs); continue; } int fieldIndex; string fieldName = null; string fieldType = null; System.Type childType = null; if (isSchema) { fieldIndex = _byte % ((operation == 0) ? 255 : operation); // FIXME: JS allows (0 || 255) ((Schema)_ref).fieldsByIndex.TryGetValue(fieldIndex, out fieldName); // fieldType = ((Schema)_ref).fieldTypes[fieldName]; ((Schema)_ref).fieldTypes.TryGetValue(fieldName ?? "", out fieldType); ((Schema)_ref).fieldChildTypes.TryGetValue(fieldName ?? "", out childType); } else { fieldName = ""; // FIXME fieldIndex = Convert.ToInt32(decode.DecodeNumber(bytes, it)); if (((ISchemaCollection)_ref).HasSchemaChild) { fieldType = "ref"; childType = ((ISchemaCollection)_ref).GetChildType(); } else { fieldType = ((ISchemaCollection)_ref).ChildPrimitiveType; } } object value = null; object previousValue = null; object dynamicIndex = null; if (!isSchema) { previousValue = _ref.GetByIndex(fieldIndex); if ((operation & (byte)OPERATION.ADD) == (byte)OPERATION.ADD) { // MapSchema dynamic index. dynamicIndex = (((ISchemaCollection)_ref).GetItems() is OrderedDictionary) ? (object)decode.DecodeString(bytes, it) : fieldIndex; ((ISchemaCollection)_ref).SetIndex(fieldIndex, dynamicIndex); } else { dynamicIndex = ((ISchemaCollection)_ref).GetIndex(fieldIndex); } } else if (fieldName != null) // FIXME: duplicate check { previousValue = ((Schema)_ref)[fieldName]; } // // Delete operations // if ((operation & (byte)OPERATION.DELETE) == (byte)OPERATION.DELETE) { if (operation != (byte)OPERATION.DELETE_AND_ADD) { _ref.DeleteByIndex(fieldIndex); } // Flag `refId` for garbage collection. if (previousValue != null && previousValue is IRef) { refs.Remove(((IRef)previousValue).__refId); } value = null; } if (fieldName == null) { // // keep skipping next bytes until reaches a known structure // by local decoder. // Iterator nextIterator = new Iterator() { Offset = it.Offset }; while (it.Offset < totalBytes) { if (decode.SwitchStructureCheck(bytes, it)) { nextIterator.Offset = it.Offset + 1; if (refs.Has(Convert.ToInt32(decode.DecodeNumber(bytes, nextIterator)))) { break; } } it.Offset++; } continue; } else if (operation == (byte)OPERATION.DELETE) { // // FIXME: refactor me. // Don't do anything. // } else if (fieldType == "ref") { refId = Convert.ToInt32(decode.DecodeNumber(bytes, it)); value = refs.Get(refId); if (operation != (byte)OPERATION.REPLACE) { var concreteChildType = GetSchemaType(bytes, it, childType); if (value == null) { value = CreateTypeInstance(concreteChildType); if (previousValue != null) { ((Schema)value).OnChange = ((Schema)previousValue).OnChange; ((Schema)value).OnRemove = ((Schema)previousValue).OnRemove; if ( ((IRef)previousValue).__refId > 0 && refId != ((IRef)previousValue).__refId ) { refs.Remove(((IRef)previousValue).__refId); } } } refs.Add(refId, (IRef)value, (value != previousValue)); } } else if (childType == null) { // primitive values value = decode.DecodePrimitiveType(fieldType, bytes, it); } else { refId = Convert.ToInt32(decode.DecodeNumber(bytes, it)); value = refs.Get(refId); ISchemaCollection valueRef = (refs.Has(refId)) ? (ISchemaCollection)previousValue : (ISchemaCollection)Activator.CreateInstance(childType); value = valueRef.Clone(); // keep reference to nested childPrimitiveType. string childPrimitiveType; ((Schema)_ref).fieldChildPrimitiveTypes.TryGetValue(fieldName, out childPrimitiveType); ((ISchemaCollection)value).ChildPrimitiveType = childPrimitiveType; if (previousValue != null) { ((ISchemaCollection)value).MoveEventHandlers(((ISchemaCollection)previousValue)); if ( ((IRef)previousValue).__refId > 0 && refId != ((IRef)previousValue).__refId ) { refs.Remove(((IRef)previousValue).__refId); var deletes = new List <DataChange>(); var items = ((ISchemaCollection)previousValue).GetItems(); foreach (var key in items.Keys) { deletes.Add(new DataChange() { DynamicIndex = key, Op = (byte)OPERATION.DELETE, Value = null, PreviousValue = items[key] }); } allChanges[(object)((IRef)previousValue).__refId] = deletes; } } refs.Add(refId, (IRef)value, (valueRef != previousValue)); } bool hasChange = (previousValue != value); if (value != null) { if (value is IRef) { ((IRef)value).__refId = refId; } if (_ref is Schema) { ((Schema)_ref)[fieldName] = value; } else if (_ref is ISchemaCollection) { ((ISchemaCollection)_ref).SetByIndex(fieldIndex, dynamicIndex, value); } } if (hasChange) { changes.Add(new DataChange { Op = operation, Field = fieldName, DynamicIndex = dynamicIndex, Value = value, PreviousValue = previousValue }); } } TriggerChanges(ref allChanges); refs.GarbageCollection(); }