/// <summary>
        /// Reads a BsonType from the reader.
        /// </summary>
        /// <returns>A BsonType.</returns>
        public override BsonType ReadBsonType()
        {
            if (disposed)
            {
                ThrowObjectDisposedException();
            }
            if (state == BsonReaderState.Initial || state == BsonReaderState.Done || state == BsonReaderState.ScopeDocument)
            {
                // there is an implied type of Document for the top level and for scope documents
                currentBsonType = BsonType.Document;
                state           = BsonReaderState.Value;
                return(currentBsonType);
            }
            if (state != BsonReaderState.Type)
            {
                ThrowInvalidState("ReadBsonType", BsonReaderState.Type);
            }

            currentBsonType = buffer.ReadBsonType();

            if (currentBsonType == BsonType.EndOfDocument)
            {
                switch (context.ContextType)
                {
                case ContextType.Array:
                    state = BsonReaderState.EndOfArray;
                    return(BsonType.EndOfDocument);

                case ContextType.Document:
                case ContextType.ScopeDocument:
                    state = BsonReaderState.EndOfDocument;
                    return(BsonType.EndOfDocument);

                default:
                    var message = string.Format("BsonType EndOfDocument is not valid when ContextType is {0}.", context.ContextType);
                    throw new FileFormatException(message);
                }
            }
            else
            {
                switch (context.ContextType)
                {
                case ContextType.Array:
                    buffer.SkipCString();     // ignore array element names
                    state = BsonReaderState.Value;
                    break;

                case ContextType.Document:
                case ContextType.ScopeDocument:
                    currentName = buffer.ReadCString();
                    state       = BsonReaderState.Name;
                    break;

                default:
                    throw new BsonInternalException("Unexpected ContextType.");
                }

                return(currentBsonType);
            }
        }
        /// <summary>
        /// Reads a BsonType from the reader.
        /// </summary>
        /// <typeparam name="TValue">The type of the BsonTrie values.</typeparam>
        /// <param name="bsonTrie">An optional trie to search for a value that matches the next element name.</param>
        /// <param name="found">Set to true if a matching value was found in the trie.</param>
        /// <param name="value">Set to the matching value found in the trie or null if no matching value was found.</param>
        /// <returns>A BsonType.</returns>
        public override BsonType ReadBsonType <TValue>(BsonTrie <TValue> bsonTrie, out bool found, out TValue value)
        {
            if (Disposed)
            {
                ThrowObjectDisposedException();
            }
            found = false;
            value = default(TValue);
            if (State == BsonReaderState.Initial || State == BsonReaderState.Done || State == BsonReaderState.ScopeDocument)
            {
                // there is an implied type of Document for the top level and for scope documents
                CurrentBsonType = BsonType.Document;
                State           = BsonReaderState.Value;
                return(CurrentBsonType);
            }
            if (State != BsonReaderState.Type)
            {
                ThrowInvalidState("ReadBsonType", BsonReaderState.Type);
            }

            CurrentBsonType = _buffer.ReadBsonType();

            if (CurrentBsonType == BsonType.EndOfDocument)
            {
                switch (_context.ContextType)
                {
                case ContextType.Array:
                    State = BsonReaderState.EndOfArray;
                    return(BsonType.EndOfDocument);

                case ContextType.Document:
                case ContextType.ScopeDocument:
                    State = BsonReaderState.EndOfDocument;
                    return(BsonType.EndOfDocument);

                default:
                    var message = string.Format("BsonType EndOfDocument is not valid when ContextType is {0}.", _context.ContextType);
                    throw new FileFormatException(message);
                }
            }
            else
            {
                switch (_context.ContextType)
                {
                case ContextType.Array:
                    _buffer.SkipCString();     // ignore array element names
                    State = BsonReaderState.Value;
                    break;

                case ContextType.Document:
                case ContextType.ScopeDocument:
                    CurrentName = _buffer.ReadCString(bsonTrie, out found, out value);
                    State       = BsonReaderState.Name;
                    break;

                default:
                    throw new BsonInternalException("Unexpected ContextType.");
                }

                return(CurrentBsonType);
            }
        }