private static <T extends Mutation> T toDelta(Function<Bytes, T> supplier,
    ConsumerWithException<T, Cell> consumer, final MutationProto proto,
    final CellScanner cellScanner) throws IOException {
    byte[] row = proto.hasRow() ? proto.getRow().toByteArray() : null;
    T mutation = row == null ? null : supplier.apply(new Bytes(row));
    int cellCount = proto.hasAssociatedCellCount() ? proto.getAssociatedCellCount() : 0;
    if (cellCount > 0) {
      // The proto has metadata only and the data is separate to be found in the cellScanner.
      if (cellScanner == null) {
        throw new DoNotRetryIOException(
          "Cell count of " + cellCount + " but no cellScanner: " + toShortString(proto));
      }
      for (int i = 0; i < cellCount; i++) {
        if (!cellScanner.advance()) {
          throw new DoNotRetryIOException("Cell count of " + cellCount + " but at index " + i
            + " no cell returned: " + toShortString(proto));
        }
        Cell cell = cellScanner.current();
        if (mutation == null) {
          mutation =
            supplier.apply(new Bytes(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
        }
        consumer.accept(mutation, cell);
      }
    } else {
      if (mutation == null) {
        throw new IllegalArgumentException("row cannot be null");
      }
      for (ColumnValue column : proto.getColumnValueList()) {
        byte[] family = column.getFamily().toByteArray();
        for (QualifierValue qv : column.getQualifierValueList()) {
          byte[] qualifier = qv.getQualifier().toByteArray();
          if (!qv.hasValue()) {
            throw new DoNotRetryIOException("Missing required field: qualifier value");
          }
          byte[] value = qv.getValue().toByteArray();
          byte[] tags = null;
          if (qv.hasTags()) {
            tags = qv.getTags().toByteArray();
          }
          consumer.accept(mutation,
            ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)
              .setRow(mutation.getRow()).setFamily(family).setQualifier(qualifier)
              .setTimestamp(cellTimestampOrLatest(qv)).setType(KeyValue.Type.Put.getCode())
              .setValue(value).setTags(tags).build());
        }
      }
    }
    mutation.setDurability(toDurability(proto.getDurability()));
    for (NameBytesPair attribute : proto.getAttributeList()) {
      mutation.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
    }
    return mutation;
  }
Convert a protocol buffer Mutate to a Delete
@param proto       the protocol buffer Mutate to convert
@param cellScanner if non-null, the data that goes with this delete.
@return the converted client Delete
hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java