github.com/consensys/gnark@v0.11.0/io/roundtrip.go (about)

     1  package io
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"io"
     7  	"reflect"
     8  )
     9  
    10  // RoundTripCheck is a helper to check that a serialization round trip is correct.
    11  // It writes the object to a buffer, then reads it back and checks that the reconstructed object is equal to the original.
    12  // It supports both io.ReaderFrom and UnsafeReaderFrom interfaces (to object)
    13  // It also supports both io.WriterTo and WriterRawTo interfaces (from object)
    14  func RoundTripCheck(from any, to func() any) error {
    15  	var buf bytes.Buffer
    16  
    17  	reconstruct := func(written int64) error {
    18  		// if builder implements io.ReaderFrom
    19  		if r, ok := to().(io.ReaderFrom); ok {
    20  			read, err := r.ReadFrom(bytes.NewReader(buf.Bytes()))
    21  			if err != nil {
    22  				return err
    23  			}
    24  			if !reflect.DeepEqual(from, r) {
    25  				return errors.New("reconstructed object don't match original (ReadFrom)")
    26  			}
    27  			if written != read {
    28  				return errors.New("bytes written / read don't match")
    29  			}
    30  		}
    31  
    32  		// if builder implements gnarkio.UnsafeReaderFrom
    33  		if r, ok := to().(UnsafeReaderFrom); ok {
    34  			read, err := r.UnsafeReadFrom(bytes.NewReader(buf.Bytes()))
    35  			if err != nil {
    36  				return err
    37  			}
    38  			if !reflect.DeepEqual(from, r) {
    39  				return errors.New("reconstructed object don't match original (UnsafeReadFrom)")
    40  			}
    41  			if written != read {
    42  				return errors.New("bytes written / read don't match")
    43  			}
    44  		}
    45  		return nil
    46  	}
    47  
    48  	// if from implements io.WriterTo
    49  	if w, ok := from.(io.WriterTo); ok {
    50  		written, err := w.WriteTo(&buf)
    51  		if err != nil {
    52  			return err
    53  		}
    54  
    55  		if err := reconstruct(written); err != nil {
    56  			return err
    57  		}
    58  	}
    59  
    60  	buf.Reset()
    61  
    62  	// if from implements gnarkio.WriterRawTo
    63  	if w, ok := from.(WriterRawTo); ok {
    64  		written, err := w.WriteRawTo(&buf)
    65  		if err != nil {
    66  			return err
    67  		}
    68  
    69  		if err := reconstruct(written); err != nil {
    70  			return err
    71  		}
    72  	}
    73  
    74  	return nil
    75  }
    76  
    77  func DumpRoundTripCheck(from any, to func() any) error {
    78  	var buf bytes.Buffer
    79  
    80  	if err := from.(BinaryDumper).WriteDump(&buf); err != nil {
    81  		return err
    82  	}
    83  
    84  	r := to().(BinaryDumper)
    85  	if err := r.ReadDump(bytes.NewReader(buf.Bytes())); err != nil {
    86  		return err
    87  	}
    88  	if !reflect.DeepEqual(from, r) {
    89  		return errors.New("reconstructed object don't match original (ReadDump)")
    90  	}
    91  	return nil
    92  }