Example #1
0
        /// <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();
            }
        }
Example #2
0
        /// <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);
        }