@@ -78,14 +78,19 @@ func generateJavaIntegration(filename string, pkgname string, srcmap *corset.Sou
7878 }
7979 // Strip suffix to determine classname
8080 classname := strings .TrimSuffix (basename , ".java" )
81+ metadata , err := binfile .Header .GetMetaData ()
82+ // Error check
83+ if err != nil {
84+ return "" , err
85+ }
8186 // begin generation
82- generateJavaHeader (pkgname , & builder )
83- generateJavaModule (classname , srcmap .Root , & binfile .Schema , indentBuilder {0 , & builder })
87+ generateJavaHeader (pkgname , metadata , & builder )
88+ generateJavaModule (classname , srcmap .Root , metadata , & binfile .Schema , indentBuilder {0 , & builder })
8489 //
8590 return builder .String (), nil
8691}
8792
88- func generateJavaHeader (pkgname string , builder * strings.Builder ) {
93+ func generateJavaHeader (pkgname string , metadata map [ string ] string , builder * strings.Builder ) {
8994 builder .WriteString (license )
9095 // Write package line
9196 if pkgname != "" {
@@ -94,9 +99,29 @@ func generateJavaHeader(pkgname string, builder *strings.Builder) {
9499 //
95100 builder .WriteString (javaImports )
96101 builder .WriteString (javaWarning )
102+ //
103+ if len (metadata ) > 0 {
104+ // Write embedded metadata for the record.
105+ builder .WriteString (" * <p>Embedded Metata</p>\n " )
106+ builder .WriteString (" * <ul>\n " )
107+ //
108+ for k , v := range metadata {
109+ builder .WriteString (" * <li>" )
110+ builder .WriteString (k )
111+ builder .WriteString (": " )
112+ builder .WriteString (v )
113+ builder .WriteString ("</li>\n " )
114+ }
115+ //
116+ builder .WriteString (" * </ul>\n " )
117+ }
118+ //
119+ builder .WriteString (" */\n " )
97120}
98121
99- func generateJavaModule (className string , mod corset.SourceModule , schema * hir.Schema , builder indentBuilder ) {
122+ func generateJavaModule (className string , mod corset.SourceModule , metadata map [string ]string , schema * hir.Schema ,
123+ builder indentBuilder ) {
124+ //
100125 var nFields uint
101126 // Attempt to find module
102127 mid , ok := schema .Modules ().Find (func (m sc.Module ) bool { return m .Name == mod .Name })
@@ -108,6 +133,11 @@ func generateJavaModule(className string, mod corset.SourceModule, schema *hir.S
108133 generateJavaClassHeader (mod .Name == "" , className , builder )
109134 generateJavaModuleConstants (mod .Constants , builder .Indent ())
110135 generateJavaModuleSubmoduleFields (mod .Submodules , builder .Indent ())
136+ //
137+ if mod .Name == "" {
138+ generateJavaModuleMetadata (metadata , builder .Indent ())
139+ }
140+ //
111141 generateJavaModuleHeaders (mid , mod , schema , builder .Indent ())
112142 //
113143 if nFields = generateJavaModuleRegisterFields (mid , schema , builder .Indent ()); nFields > 0 {
@@ -125,7 +155,7 @@ func generateJavaModule(className string, mod corset.SourceModule, schema *hir.S
125155 // Generate any submodules
126156 for _ , submod := range mod .Submodules {
127157 if ! submod .Virtual {
128- generateJavaModule (toPascalCase (submod .Name ), submod , schema , builder .Indent ())
158+ generateJavaModule (toPascalCase (submod .Name ), submod , metadata , schema , builder .Indent ())
129159 } else {
130160 generateJavaModuleColumnSetters (className , submod , schema , builder .Indent ())
131161 }
@@ -323,6 +353,23 @@ func generateJavaModuleSubmoduleFields(submodules []corset.SourceModule, builder
323353 }
324354}
325355
356+ func generateJavaModuleMetadata (metadata map [string ]string , builder indentBuilder ) {
357+ // Write field declaration
358+ builder .WriteIndentedString ("public static Map<String,String> metadata() {\n " )
359+ // Initialise map using Java static initialiser
360+ if len (metadata ) > 0 {
361+ i1Builder := builder .Indent ()
362+ i1Builder .WriteIndentedString ("Map<String,String> metadata = new HashMap<>();\n " )
363+
364+ for k , v := range metadata {
365+ i1Builder .WriteIndentedString ("metadata.put(\" " , k , "\" ,\" " , v , "\" );\n " )
366+ }
367+ //
368+ i1Builder .WriteIndentedString ("return metadata;\n " )
369+ builder .WriteIndentedString ("}\n \n " )
370+ }
371+ }
372+
326373func generateJavaModuleConstructor (classname string , mid uint , mod corset.SourceModule ,
327374 schema * hir.Schema , builder indentBuilder ) {
328375 //
@@ -686,24 +733,28 @@ const javaWarning string = `
686733 * WARNING: This code is generated automatically.
687734 *
688735 * <p>Any modifications to this code may be overwritten and could lead to unexpected behavior.
689- * Please DO NOT ATTEMPT TO MODIFY this code directly.
690- */
736+ * Please DO NOT ATTEMPT TO MODIFY this code directly</p> .
737+ *
691738`
692739
693740const javaImports string = `
694741import java.io.IOException;
695742import java.io.RandomAccessFile;
696743import java.math.BigInteger;
744+ import java.nio.ByteBuffer;
697745import java.nio.MappedByteBuffer;
698746import java.nio.channels.FileChannel;
699747import java.util.ArrayList;
700748import java.util.BitSet;
749+ import java.util.HashMap;
701750import java.util.List;
751+ import java.util.Map;
702752
703753import net.consensys.linea.zktracer.types.UnsignedByte;
704754import org.apache.tuweni.bytes.Bytes;
705755`
706756
757+ // nolint
707758const javaTraceOf string = `
708759 /**
709760 * Construct a new trace which will be written to a given file.
@@ -713,21 +764,46 @@ const javaTraceOf string = `
713764 *
714765 * @throws IOException If an I/O error occurs.
715766 */
716- public static Trace of(RandomAccessFile file, List<ColumnHeader> rawHeaders) throws IOException {
717- // First align headers according to register indices.
718- ColumnHeader[] headers = alignHeaders(rawHeaders);
719- // Second determine file size
720- long headerSize = determineHeaderSize(headers);
721- long dataSize = determineHeaderSize(headers);
767+ public static Trace of(RandomAccessFile file, List<ColumnHeader> rawHeaders, byte[] metadata) throws IOException {
768+ // Construct trace file header bytes
769+ byte[] header = constructTraceFileHeader(metadata);
770+ // Align headers according to register indices.
771+ ColumnHeader[] columnHeaders = alignHeaders(rawHeaders);
772+ // Determine file size
773+ long headerSize = determineColumnHeadersSize(columnHeaders) + header.length;
774+ long dataSize = determineColumnDataSize(columnHeaders);
722775 file.setLength(headerSize + dataSize);
723- // Write header
724- writeHeader (file,headers ,headerSize);
776+ // Write headers
777+ writeHeaders (file,header,columnHeaders ,headerSize);
725778 // Initialise buffers
726- MappedByteBuffer[] buffers = initialiseByteBuffers(file,headers ,headerSize);
779+ MappedByteBuffer[] buffers = initialiseByteBuffers(file,columnHeaders ,headerSize);
727780 // Done
728781 return new Trace(buffers);
729782 }
730783
784+ /**
785+ * Construct trace file header containing the given metadata bytes.
786+ *
787+ * @param metadata Metadata bytes to be embedded in the trace file.
788+ *
789+ * @return bytes making up the header.
790+ */
791+ private static byte[] constructTraceFileHeader(byte[] metadata) {
792+ ByteBuffer buffer = ByteBuffer.allocate(16 + metadata.length);
793+ // File identifier
794+ buffer.put(new byte[]{'z','k','t','r','a','c','e','r'});
795+ // Major version
796+ buffer.putShort((short) 1);
797+ // Minor version
798+ buffer.putShort((short) 0);
799+ // Metadata length
800+ buffer.putInt(metadata.length);
801+ // Metadata
802+ buffer.put(metadata);
803+ // Done
804+ return buffer.array();
805+ }
806+
731807 /**
732808 * Align headers ensures that the order in which columns are seen matches the order found in the trace schema.
733809 *
@@ -750,7 +826,7 @@ const javaTraceOf string = `
750826 * @param headers Set of headers for the columns being written.
751827 * @return Number of bytes requires for the trace file header.
752828 */
753- private static long determineHeaderSize (ColumnHeader[] headers) {
829+ private static long determineColumnHeadersSize (ColumnHeader[] headers) {
754830 long nBytes = 4; // column count
755831
756832 for (ColumnHeader header : headers) {
@@ -769,7 +845,7 @@ const javaTraceOf string = `
769845 * @param headers Set of headers for the columns being written.
770846 * @return Number of bytes required for storing all column data, excluding the header.
771847 */
772- private static long determineDataSize (ColumnHeader[] headers) {
848+ private static long determineColumnDataSize (ColumnHeader[] headers) {
773849 long nBytes = 0;
774850
775851 for (ColumnHeader header : headers) {
@@ -781,20 +857,24 @@ const javaTraceOf string = `
781857
782858 /**
783859 * Write header information for the trace file.
860+ *
784861 * @param file Trace file being written.
862+ * @param header Trace file header
785863 * @param headers Column headers.
786864 * @param size Overall size of the header.
787865 */
788- private static void writeHeader(RandomAccessFile file, ColumnHeader[] headers, long size) throws IOException {
789- final var header = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, size);
866+ private static void writeHeaders(RandomAccessFile file, byte[] header, ColumnHeader[] headers, long size) throws IOException {
867+ final var buffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, size);
868+ // Write trace file header
869+ buffer.put(header);
790870 // Write column count as uint32
791- header .putInt(headers.length);
871+ buffer .putInt(headers.length);
792872 // Write column headers one-by-one
793873 for(ColumnHeader h : headers) {
794- header .putShort((short) h.name.length());
795- header .put(h.name.getBytes());
796- header .put((byte) h.bytesPerElement);
797- header .putInt((int) h.length);
874+ buffer .putShort((short) h.name.length());
875+ buffer .put(h.name.getBytes());
876+ buffer .put((byte) h.bytesPerElement);
877+ buffer .putInt((int) h.length);
798878 }
799879 }
800880
0 commit comments