public void WriteToken(BsonToken t)
 {
     CalculateSize(t);
     WriteTokenInternal(t);
 }
        private void WriteTokenInternal(BsonToken t)
        {
            switch (t.Type)
            {
            case BsonType.Object:
            {
                BsonObject value = (BsonObject)t;
                _writer.Write(value.CalculatedSize);
                foreach (BsonProperty property in value)
                {
                    _writer.Write((sbyte)property.Value.Type);
                    WriteString((string)property.Name.Value, property.Name.ByteCount, null);
                    WriteTokenInternal(property.Value);
                }
                _writer.Write((byte)0);
            }
            break;

            case BsonType.Array:
            {
                BsonArray value = (BsonArray)t;
                _writer.Write(value.CalculatedSize);
                ulong index = 0;
                foreach (BsonToken c in value)
                {
                    _writer.Write((sbyte)c.Type);
                    WriteString(index.ToString(CultureInfo.InvariantCulture), MathUtils.IntLength(index), null);
                    WriteTokenInternal(c);
                    index++;
                }
                _writer.Write((byte)0);
            }
            break;

            case BsonType.Integer:
            {
                BsonValue value = (BsonValue)t;
                _writer.Write(Convert.ToInt32(value.Value, CultureInfo.InvariantCulture));
            }
            break;

            case BsonType.Long:
            {
                BsonValue value = (BsonValue)t;
                _writer.Write(Convert.ToInt64(value.Value, CultureInfo.InvariantCulture));
            }
            break;

            case BsonType.Number:
            {
                BsonValue value = (BsonValue)t;
                _writer.Write(Convert.ToDouble(value.Value, CultureInfo.InvariantCulture));
            }
            break;

            case BsonType.String:
            {
                BsonString value = (BsonString)t;
                WriteString((string)value.Value, value.ByteCount, value.CalculatedSize - 4);
            }
            break;

            case BsonType.Boolean:
            {
                BsonValue value = (BsonValue)t;
                _writer.Write((bool)value.Value);
            }
            break;

            case BsonType.Null:
            case BsonType.Undefined:
                break;

            case BsonType.Date:
            {
                BsonValue value = (BsonValue)t;

                long ticks = 0;

                if (value.Value is DateTime)
                {
                    DateTime dateTime = (DateTime)value.Value;
                    if (DateTimeKindHandling == DateTimeKind.Utc)
                    {
                        dateTime = dateTime.ToUniversalTime();
                    }
                    else if (DateTimeKindHandling == DateTimeKind.Local)
                    {
                        dateTime = dateTime.ToLocalTime();
                    }

                    ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(dateTime, false);
                }
#if !NET20
                else
                {
                    DateTimeOffset dateTimeOffset = (DateTimeOffset)value.Value;
                    ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(dateTimeOffset.UtcDateTime, dateTimeOffset.Offset);
                }
#endif

                _writer.Write(ticks);
            }
            break;

            case BsonType.Binary:
            {
                BsonBinary value = (BsonBinary)t;

                byte[] data = (byte[])value.Value;
                _writer.Write(data.Length);
                _writer.Write((byte)value.BinaryType);
                _writer.Write(data);
            }
            break;

            case BsonType.Oid:
            {
                BsonValue value = (BsonValue)t;

                byte[] data = (byte[])value.Value;
                _writer.Write(data);
            }
            break;

            case BsonType.Regex:
            {
                BsonRegex value = (BsonRegex)t;

                WriteString((string)value.Pattern.Value, value.Pattern.ByteCount, null);
                WriteString((string)value.Options.Value, value.Options.ByteCount, null);
            }
            break;

            default:
                throw new ArgumentOutOfRangeException(nameof(t), "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
            }
        }
        private int CalculateSize(BsonToken t)
        {
            switch (t.Type)
            {
            case BsonType.Object:
            {
                BsonObject value = (BsonObject)t;

                int bases = 4;
                foreach (BsonProperty p in value)
                {
                    int size = 1;
                    size += CalculateSize(p.Name);
                    size += CalculateSize(p.Value);

                    bases += size;
                }
                bases += 1;
                value.CalculatedSize = bases;
                return(bases);
            }

            case BsonType.Array:
            {
                BsonArray value = (BsonArray)t;

                int   size  = 4;
                ulong index = 0;
                foreach (BsonToken c in value)
                {
                    size += 1;
                    size += CalculateSize(MathUtils.IntLength(index));
                    size += CalculateSize(c);
                    index++;
                }
                size += 1;
                value.CalculatedSize = size;

                return(value.CalculatedSize);
            }

            case BsonType.Integer:
                return(4);

            case BsonType.Long:
                return(8);

            case BsonType.Number:
                return(8);

            case BsonType.String:
            {
                BsonString value = (BsonString)t;
                string     s     = (string)value.Value;
                value.ByteCount      = (s != null) ? Encoding.GetByteCount(s) : 0;
                value.CalculatedSize = CalculateSizeWithLength(value.ByteCount, value.IncludeLength);

                return(value.CalculatedSize);
            }

            case BsonType.Boolean:
                return(1);

            case BsonType.Null:
            case BsonType.Undefined:
                return(0);

            case BsonType.Date:
                return(8);

            case BsonType.Binary:
            {
                BsonBinary value = (BsonBinary)t;

                byte[] data = (byte[])value.Value;
                value.CalculatedSize = 4 + 1 + data.Length;

                return(value.CalculatedSize);
            }

            case BsonType.Oid:
                return(12);

            case BsonType.Regex:
            {
                BsonRegex value = (BsonRegex)t;
                int       size  = 0;
                size += CalculateSize(value.Pattern);
                size += CalculateSize(value.Options);
                value.CalculatedSize = size;

                return(value.CalculatedSize);
            }

            default:
                throw new ArgumentOutOfRangeException(nameof(t), "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
            }
        }