public string BuildString()
        {
            End();
            var result = NS2Bridge.CreateString(_jwtLength, _jwt, (destination, state) => {
                NS2Bridge.Latin1ToUtf16(state.AsSpan(0, _jwtLength), destination);
            });

            return(result);
        }
 public bool TryBuildTo(Span <char> destination, out int charsWritten)
 {
     End();
     if (destination.Length < _jwtLength)
     {
         charsWritten = 0;
         return(false);
     }
     NS2Bridge.Latin1ToUtf16(_jwt.AsSpan(0, _jwtLength), destination);
     charsWritten = _jwtLength;
     return(true);
 }
        /// <summary>
        /// Returns number of ASCII characters of the JTW. The actual token can be retrieved using Build or WriteTo
        /// </summary>
        /// <returns></returns>
        public int End()
        {
            if (_writer == null)
            {
                return(_jwtLength);                 // writer is set to null after token is formatted.
            }
            if (_isDisposed)
            {
                throw new ObjectDisposedException(nameof(JwtBuilder));
            }

            _writer.WriteEndObject();
            _writer.Flush();

            Debug.Assert(_memoryStream.GetType() == typeof(MemoryStream));
            int payloadLength = (int)_writer.BytesCommitted; // writer is wrrapping MemoryStream, and so the length will never overflow int.

            int payloadIndex = headerSha256.Length;

            int maxBufferLength;

            checked {
                maxBufferLength =
                    Base64.GetMaxEncodedToUtf8Length(headerSha256.Length + payloadLength)
                    + 1                                     // dot
                    + Base64.GetMaxEncodedToUtf8Length(32); // signature SHA256 hash size
            }
            _memoryStream.Capacity = maxBufferLength;       // make room for in-place Base64 conversion

            _jwt    = _memoryStream.GetBuffer();
            _writer = null; // this will prevent subsequent additions of claims.

            Span <byte>     toEncode = _jwt.AsSpan(payloadIndex);
            OperationStatus status   = NS2Bridge.Base64UrlEncodeInPlace(toEncode, payloadLength, out int payloadWritten);

            Debug.Assert(status == OperationStatus.Done); // Buffer is adjusted above, and so encoding should always fit

            // Add signature
            int headerAndPayloadLength = payloadWritten + headerSha256.Length;

            _jwt[headerAndPayloadLength] = (byte)'.';
            int headerAndPayloadAndSeparatorLength = headerAndPayloadLength + 1;

            using (HMACSHA256 hash = new HMACSHA256(_key))
            {
                var hashed = hash.ComputeHash(_jwt, 0, headerAndPayloadLength);
                status = NS2Bridge.Base64UrlEncode(hashed, _jwt.AsSpan(headerAndPayloadAndSeparatorLength), out int consumend, out int signatureLength);
                Debug.Assert(status == OperationStatus.Done); // Buffer is adjusted above, and so encoding should always fit
                _jwtLength = headerAndPayloadAndSeparatorLength + signatureLength;
            }

            return(_jwtLength);
        }