/// <summary> /// Prepare the field name and annotations (if any) /// </summary> /// <remarks>This method should implemented in a way that it can be called multiple times and still remains the correct state</remarks> private void PrepareValue() { if (IsInStruct && _currentFieldSymbolToken == default) { throw new InvalidOperationException("In a struct but field name is not set"); } if (_currentFieldSymbolToken != default) { //write field name id WriteVarUint(_currentFieldSymbolToken.Sid); _currentFieldSymbolToken = default; } if (_annotations.Count > 0) { //Since annotations 'wraps' the actual value, we basically won't know the length //(the upcoming value might be another container) //so we treat this as another container of type 'annotation' //add all written segments to the sequence _dataBuffer.Wrapup(); //set a new container var newContainer = _containerStack.PushContainer(ContainerType.Annotation); _dataBuffer.StartStreak(newContainer.Sequence); var annotLength = _dataBuffer.WriteAnnotationsWithLength(_annotations); _containerStack.IncreaseCurrentContainerLength(annotLength); _annotations.Clear(); } }
/// <summary> /// Pop a container from the container stack and link the previous container sequence with the length /// and sequence of the popped container /// </summary> private void PopContainer() { var popped = _containerStack.Pop(); if (_containerStack.Count == 0) { return; } var wrappedList = _dataBuffer.Wrapup(); Debug.Assert(ReferenceEquals(wrappedList, popped.Sequence)); var outer = _containerStack.Peek(); //write the tid|len byte and (maybe) the length into the length buffer //clear the length segments, no worry _lengthSegments.Clear(); _lengthBuffer.StartStreak(_lengthSegments); byte tidByte; switch (popped.Type) { case ContainerType.Sequence: tidByte = TidListByte; break; case ContainerType.Struct: tidByte = TidStructByte; break; case ContainerType.Annotation: tidByte = TidTypeDeclByte; break; case ContainerType.Timestamp: tidByte = TidTimestampByte; break; case ContainerType.BigDecimal: tidByte = TidDecimalByte; break; default: throw new ArgumentOutOfRangeException(); } var wholeContainerLength = popped.Length; if (wholeContainerLength <= 0xD) { //fit in the tid byte tidByte |= (byte)wholeContainerLength; _containerStack.IncreaseCurrentContainerLength(1 + wholeContainerLength); _lengthBuffer.WriteByte(tidByte); } else { tidByte |= BinaryConstants.LnIsVarLen; _lengthBuffer.WriteByte(tidByte); var lengthBytes = _lengthBuffer.WriteVarUint(popped.Length); _containerStack.IncreaseCurrentContainerLength(1 + lengthBytes + wholeContainerLength); } _lengthBuffer.Wrapup(); foreach (var t in _lengthSegments) { outer.Sequence.Add(t); } outer.Sequence.AddRange(wrappedList); _dataBuffer.StartStreak(outer.Sequence); }