public static Result toResult(final ClientProtos.Result proto, final CellScanner scanner)
    throws IOException {
    List<CellProtos.Cell> values = proto.getCellList();

    if (proto.hasExists()) {
      if (
        (values != null && !values.isEmpty())
          || (proto.hasAssociatedCellCount() && proto.getAssociatedCellCount() > 0)
      ) {
        throw new IllegalArgumentException("bad proto: exists with cells is no allowed " + proto);
      }
      if (proto.getStale()) {
        return proto.getExists() ? EMPTY_RESULT_EXISTS_TRUE_STALE : EMPTY_RESULT_EXISTS_FALSE_STALE;
      }
      return proto.getExists() ? EMPTY_RESULT_EXISTS_TRUE : EMPTY_RESULT_EXISTS_FALSE;
    }

    // TODO: Unit test that has some Cells in scanner and some in the proto.
    List<Cell> cells = null;
    if (proto.hasAssociatedCellCount()) {
      int count = proto.getAssociatedCellCount();
      cells = new ArrayList<>(count + values.size());
      for (int i = 0; i < count; i++) {
        if (!scanner.advance()) throw new IOException("Failed get " + i + " of " + count);
        cells.add(scanner.current());
      }
    }

    if (!values.isEmpty()) {
      if (cells == null) cells = new ArrayList<>(values.size());
      ExtendedCellBuilder builder = ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY);
      for (CellProtos.Cell c : values) {
        cells.add(toCell(builder, c, false));
      }
    }

    Result r = (cells == null || cells.isEmpty())
      ? (proto.getStale() ? EMPTY_RESULT_STALE : EMPTY_RESULT)
      : Result.create(cells, null, proto.getStale());

    if (proto.hasMetrics()) {
      r.setMetrics(toQueryMetrics(proto.getMetrics()));
    }

    return r;
  }
Convert a protocol buffer Result to a client Result
@param proto   the protocol buffer Result to convert
@param scanner Optional cell scanner.
@return the converted client Result
hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java