code: public void readIntegers(
        int total,
        WritableColumnVector c,
        int rowId,
        int level,
        VectorizedValuesReader data) throws IOException {
      int left = total;
      while (left > 0) {
        if (this.currentCount == 0) this.readNextGroup();
        int n = Math.min(left, this.currentCount);
        switch (mode) {
          case RLE:
            if (currentValue == level) {
              data.readIntegers(n, c, rowId);
            } else {
              c.putNulls(rowId, n);
            }
            break;
          case PACKED:
            for (int i = 0; i < n; ++i) {
              if (currentBuffer[currentBufferIdx++] == level) {
                c.putInt(rowId + i, data.readInteger());
              } else {
                c.putNull(rowId + i);
              }
            }
            break;
        }
        rowId += n;
        left -= n;
        currentCount -= n;
      }
    }
docs: Reads `total` ints into `c` filling them in starting at `c[rowId]`. This reader
  reads the definition levels and then will read from `data` for the non-null values.
  If the value is null, c will be populated with `nullValue`. Note that `nullValue` is only
  necessary for readIntegers because we also use it to decode dictionaryIds and want to make
  sure it always has a value in range.
  
  This is a batched version of this logic:
  if (this.readInt() == level) {
  c[rowId] = data.readInteger();
  } else {
  c[rowId] = null;
  }