cdm/src/main/java/ucar/nc2/stream/NcStreamDataRow.java
NcStreamProto.ArrayStructureRow.Builder encodeStructureData(String structName, Array data) {
    assert data instanceof ArrayStructure;
    ArrayStructure as = (ArrayStructure) data;
    int nelems = (int) as.getSize();

    List<MemberData> memberData = new ArrayList<>();
    StructureMembers sm = as.getStructureMembers();
    for (StructureMembers.Member m : sm.getMembers()) {
      memberData.add( new MemberData(m, nelems));
    }

    // use most efficient form of data extraction
    for (int recno=0; recno<nelems; recno++) {
      for (MemberData md : memberData) {
        if (md.member.isVariableLength()) {
          md.vlenList.add(as.getArray(recno, md.member));
        } else {
          extractData(as, recno, md);
        }
      }
    }

    NcStreamProto.ArrayStructureRow.Builder builder = NcStreamProto.ArrayStructureRow.newBuilder();
    for (MemberData md : memberData) {
      NcStreamProto.Member.Builder member = NcStreamProto.Member.newBuilder();
      member.setShortName(md.member.getName());
      member.setDataType(NcStream.convertDataType(md.member.getDataType()));
      /* LOOK
      member.setNelems(md.nelems);
      if (md.member.isVariableLength()) {
        md.completeVlens();
        nested.addAllVlens (md.vlens);
        nested.setPrimdata(ByteString.copyFrom(md.bb));

      } else if (md.member.getDataType() == DataType.STRING)
        nested.addAllStringdata(md.stringList);
      else if (md.member.getDataType() == DataType.OPAQUE)
        nested.addAllOpaquedata(md.opaqueList);
      else
        nested.setPrimdata(ByteString.copyFrom(md.bb)); */

      builder.addMembers(member);
    }

    return builder;
  }
NcStreamProto.ArrayStructureRow.Builder encodeStructureData(String structName, Array data) {
    assert data instanceof ArrayStructure;
    ArrayStructure as = (ArrayStructure) data;
    int nelems = (int) as.getSize();

    List<MemberData> memberData = new ArrayList<>();
    StructureMembers sm = as.getStructureMembers();
    for (StructureMembers.Member m : sm.getMembers()) {
      memberData.add( new MemberData(m, nelems));
    }

    // use most efficient form of data extraction
    for (int recno=0; recno<nelems; recno++) {
      for (MemberData md : memberData) {
        if (md.member.isVariableLength()) {
          md.vlenList.add(as.getArray(recno, md.member));
        } else {
          extractData(as, recno, md);
        }
      }
    }

    NcStreamProto.ArrayStructureRow.Builder builder = NcStreamProto.ArrayStructureRow.newBuilder();
    for (MemberData md : memberData) {
      NcStreamProto.Member.Builder member = NcStreamProto.Member.newBuilder();
      member.setShortName(md.member.getName());
      member.setDataType(NcStream.convertDataType(md.member.getDataType()));
      /* LOOK
      member.setNelems(md.nelems);
      if (md.member.isVariableLength()) {
        md.completeVlens();
        nested.addAllVlens (md.vlens);
        nested.setPrimdata(ByteString.copyFrom(md.bb));

      } else if (md.member.getDataType() == DataType.STRING)
        nested.addAllStringdata(md.stringList);
      else if (md.member.getDataType() == DataType.OPAQUE)
        nested.addAllOpaquedata(md.opaqueList);
      else
        nested.setPrimdata(ByteString.copyFrom(md.bb)); */

      builder.addMembers(member);
    }

    return builder;
  }
NcStreamProto . ArrayStructureRow . Builder encodeStructureData ( String structName , Array data ) { assert data instanceof ArrayStructure ; ArrayStructure as = ( ArrayStructure ) data ; int nelems = ( int ) as . getSize ( ) ; List < MemberData > memberData = new ArrayList <> ( ) ; StructureMembers sm = as . getStructureMembers ( ) ; for ( StructureMembers . Member m : sm . getMembers ( ) ) { memberData . add ( new MemberData ( m , nelems ) ) ; } // use most efficient form of data extraction for ( int recno = 0 ; recno < nelems ; recno ++ ) { for ( MemberData md : memberData ) { if ( md . member . isVariableLength ( ) ) { md . vlenList . add ( as . getArray ( recno , md . member ) ) ; } else { extractData ( as , recno , md ) ; } } } NcStreamProto . ArrayStructureRow . Builder builder = NcStreamProto . ArrayStructureRow . newBuilder ( ) ; for ( MemberData md : memberData ) { NcStreamProto . Member . Builder member = NcStreamProto . Member . newBuilder ( ) ; member . setShortName ( md . member . getName ( ) ) ; member . setDataType ( NcStream . convertDataType ( md . member . getDataType ( ) ) ) ; /* LOOK
      member.setNelems(md.nelems);
      if (md.member.isVariableLength()) {
        md.completeVlens();
        nested.addAllVlens (md.vlens);
        nested.setPrimdata(ByteString.copyFrom(md.bb));

      } else if (md.member.getDataType() == DataType.STRING)
        nested.addAllStringdata(md.stringList);
      else if (md.member.getDataType() == DataType.OPAQUE)
        nested.addAllOpaquedata(md.opaqueList);
      else
        nested.setPrimdata(ByteString.copyFrom(md.bb)); */ builder . addMembers ( member ) ; } return builder ; }
/*
message Member {
string shortName = 1;
DataType dataType = 2;
repeated uint32 shape = 3;  // or section?
bool isVlen = 4;
}

message ArrayStructureRow {
repeated Member members = 1;
uint64 nrows = 5;      // number of rows in this message
uint32 rowLength = 6;  // length in bytes of each row

bytes fixdata = 10;            // fixed data
repeated string stringdata = 11;  // string dataType
repeated bytes bytedata = 13;  // opaque dataType and vlens
repeated ArrayStructureRow structdata = 14;  // structure/seq dataType
}
/ * message Member { string shortName = 1 ; DataType dataType = 2 ; repeated uint32 shape = 3 ; // or section? bool isVlen = 4 ; }