gt:       final int codeWsStart = arg.writerIndex();
context: /*
   * Copyright 2014 8Kdata Technology
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package com.torodb.mongowp.bson.netty;
  
  import com.google.common.base.Charsets;
  import com.google.common.primitives.UnsignedInteger;
  import com.torodb.mongowp.bson.BsonArray;
  import com.torodb.mongowp.bson.BsonBinary;
  import com.torodb.mongowp.bson.BsonBoolean;
  import com.torodb.mongowp.bson.BsonDateTime;
  import com.torodb.mongowp.bson.BsonDbPointer;
  import com.torodb.mongowp.bson.BsonDecimal128;
  import com.torodb.mongowp.bson.BsonDeprecated;
  import com.torodb.mongowp.bson.BsonDocument;
  import com.torodb.mongowp.bson.BsonDocument.Entry;
  import com.torodb.mongowp.bson.BsonDouble;
  import com.torodb.mongowp.bson.BsonInt32;
  import com.torodb.mongowp.bson.BsonInt64;
  import com.torodb.mongowp.bson.BsonJavaScript;
  import com.torodb.mongowp.bson.BsonJavaScriptWithScope;
  import com.torodb.mongowp.bson.BsonMax;
  import com.torodb.mongowp.bson.BsonMin;
  import com.torodb.mongowp.bson.BsonNull;
  import com.torodb.mongowp.bson.BsonObjectId;
  import com.torodb.mongowp.bson.BsonRegex;
  import com.torodb.mongowp.bson.BsonString;
  import com.torodb.mongowp.bson.BsonTimestamp;
  import com.torodb.mongowp.bson.BsonUndefined;
  import com.torodb.mongowp.bson.BsonValue;
  import com.torodb.mongowp.bson.BsonValueVisitor;
  import com.torodb.mongowp.bson.utils.NonIoByteSource;
  import io.netty.buffer.ByteBuf;
  import io.netty.buffer.ByteBufOutputStream;
  
  import java.io.IOException;
  import java.io.OutputStream;
  
  import javax.annotation.concurrent.ThreadSafe;
  
  /**
   *
   */
  @ThreadSafe
  public class NettyBsonDocumentWriter {
  
    private static final WriterBsonValueVisitor VISITOR = new WriterBsonValueVisitor();
  
    public void writeInto(ByteBuf byteBuf, BsonDocument doc) {
      doc.accept(VISITOR, byteBuf);
    }
  
    private static class WriterBsonValueVisitor implements BsonValueVisitor<Void, ByteBuf> {
  
      void writeCString(ByteBuf buf, String str) {
        buf.writeBytes(str.getBytes(Charsets.UTF_8));
        buf.writeByte(0x00);
      }
  
      void writeString(ByteBuf buf, String str) {
        byte[] bytes = str.getBytes(Charsets.UTF_8);
        int length = bytes.length + 1;
  
        buf.writeInt(length).writeBytes(bytes).writeByte(0x00);
      }
  
      @Override
      public Void visit(BsonArray value, ByteBuf arg) {
        final int docStart = arg.writerIndex();
        arg.writeInt(0); // reserve space for doc size
  
        int i = 0;
        for (BsonValue<?> child : value) {
          try {
            arg.writeByte(ParsingTools.getByte(child.getType()));
          } catch (NettyBsonReaderException ex) {
            throw new AssertionError(ex);
          }
          writeCString(arg, Integer.toString(i));
  
          child.accept(this, arg);
          i++;
        }
  
        arg.writeByte(0x00);
  
        int docEnd = arg.writerIndex();
  
        arg.writerIndex(docStart).writeInt(docEnd - docStart).writerIndex(docEnd);
  
        return null;
      }
  
      @Override
      public Void visit(BsonBinary value, ByteBuf arg) {
        NonIoByteSource byteSource = value.getByteSource();
  
        UnsignedInteger unsignedSize;
        unsignedSize = UnsignedInteger.valueOf(byteSource.size());
  
        arg.writeInt(unsignedSize.intValue()).writeByte(value.getNumericSubType());
  
        try (OutputStream os = new ByteBufOutputStream(arg)) {
          value.getByteSource().copyTo(os);
        } catch (IOException ex) {
          throw new AssertionError("Unexpected IOException", ex);
        }
        return null;
      }
  
      @Override
      public Void visit(BsonDbPointer value, ByteBuf arg) {
        writeString(arg, value.getNamespace());
        value.getId().accept(this, arg);
  
        return null;
      }
  
      @Override
      public Void visit(BsonDateTime value, ByteBuf arg) {
        arg.writeLong(value.getMillisFromUnix());
  
        return null;
      }
  
      @Override
      public Void visit(BsonDocument value, ByteBuf arg) {
        final int docStart = arg.writerIndex();
        arg.writeInt(0); // reserve space for doc size
  
        for (Entry<?> entry : value) {
          BsonValue<?> child = entry.getValue();
          try {
            arg.writeByte(ParsingTools.getByte(child.getType()));
          } catch (NettyBsonReaderException ex) {
            throw new AssertionError(ex);
          }
          writeCString(arg, entry.getKey());
  
          child.accept(this, arg);
        }
  
        arg.writeByte(0x00);
  
        int docEnd = arg.writerIndex();
  
        arg.writerIndex(docStart).writeInt(docEnd - docStart).writerIndex(docEnd);
  
        return null;
      }
  
      @Override
      public Void visit(BsonDouble value, ByteBuf arg) {
        arg.writeDouble(value.doubleValue());
  
        return null;
      }
  
      @Override
      public Void visit(BsonInt32 value, ByteBuf arg) {
        arg.writeInt(value.intValue());
  
        return null;
      }
  
      @Override
      public Void visit(BsonInt64 value, ByteBuf arg) {
        arg.writeLong(value.longValue());
  
        return null;
      }
  
      @Override
      public Void visit(BsonBoolean value, ByteBuf arg) {
        if (value.getPrimitiveValue()) {
          arg.writeByte(0x01);
        } else {
          arg.writeByte(0x00);
        }
        return null;
      }
  
      @Override
      public Void visit(BsonJavaScript value, ByteBuf arg) {
        writeString(arg, value.getValue());
  
        return null;
      }
  
      @Override
      public Void visit(BsonJavaScriptWithScope value, ByteBuf arg) {
  