github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/kit/httptransport/transformer/tsfm_super.go (about)

     1  package transformer
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"reflect"
     7  
     8  	pkgerr "github.com/pkg/errors"
     9  
    10  	vldterr "github.com/machinefi/w3bstream/pkg/depends/kit/validator/errors"
    11  	"github.com/machinefi/w3bstream/pkg/depends/x/reflectx"
    12  )
    13  
    14  func NewSuper(tsfm Transformer, opt *CommonOption) *Super {
    15  	return &Super{
    16  		tsfm:         tsfm,
    17  		CommonOption: *opt,
    18  	}
    19  }
    20  
    21  type Super struct {
    22  	tsfm Transformer
    23  	CommonOption
    24  }
    25  
    26  func (t *Super) EncodeTo(ctx context.Context, w io.Writer, v interface{}) error {
    27  	rv, ok := v.(reflect.Value)
    28  	if !ok {
    29  		rv = reflect.ValueOf(v)
    30  	}
    31  
    32  	if t.Explode {
    33  		rv = reflectx.Indirect(rv)
    34  		// for create slice
    35  		if setter, ok := w.(interface{ SetN(n int) }); ok {
    36  			setter.SetN(rv.Len())
    37  		}
    38  
    39  		if next, ok := w.(CanNextWriter); ok {
    40  			errs := vldterr.NewErrorSet()
    41  			for i := 0; i < rv.Len(); i++ {
    42  				nw := next.NextWriter()
    43  				if err := t.tsfm.EncodeTo(ctx, nw, rv.Index(i)); err != nil {
    44  					errs.AddErr(err, i)
    45  				}
    46  			}
    47  			return errs.Err()
    48  		}
    49  		return nil
    50  	}
    51  
    52  	// should skip empty value when omitempty
    53  	if !(t.Omitempty && reflectx.IsEmptyValue(rv)) {
    54  		writer, ok := w.(CanNextWriter)
    55  		if ok {
    56  			return t.tsfm.EncodeTo(ctx, writer.NextWriter(), rv)
    57  		}
    58  		return t.tsfm.EncodeTo(ctx, w, rv)
    59  	}
    60  
    61  	return nil
    62  }
    63  
    64  func (t *Super) DecodeFrom(ctx context.Context, r io.Reader, v interface{}) error {
    65  	if rv, ok := v.(reflect.Value); ok {
    66  		v = rv.Interface()
    67  	}
    68  
    69  	if reflect.TypeOf(v).Kind() != reflect.Ptr {
    70  		return pkgerr.Errorf("decode target must be ptr value")
    71  	}
    72  
    73  	if t.Explode {
    74  		valc := 0
    75  		if with, ok := r.(interface{ Len() int }); ok {
    76  			valc = with.Len()
    77  		}
    78  		if valc == 0 {
    79  			return nil
    80  		}
    81  		if x, ok := v.(*[]string); ok {
    82  			if with, ok := r.(CanInterface); ok {
    83  				if values, ok := with.Interface().([]string); ok {
    84  					*x = values
    85  					return nil
    86  				}
    87  			}
    88  		}
    89  
    90  		rv := reflectx.Indirect(reflect.ValueOf(v))
    91  
    92  		// make slice (ignore array)
    93  		if rv.Kind() == reflect.Slice {
    94  			rv.Set(reflect.MakeSlice(rv.Type(), valc, valc))
    95  		}
    96  
    97  		reader, ok := r.(CanNextReader)
    98  		if !ok {
    99  			return nil
   100  		}
   101  
   102  		errs := vldterr.NewErrorSet()
   103  		// ignore when values length greater than array len
   104  		for i := 0; i < rv.Len() && i < valc; i++ {
   105  			if err := t.tsfm.DecodeFrom(
   106  				ctx,
   107  				reader.NextReader(),
   108  				rv.Index(i).Addr(),
   109  			); err != nil {
   110  				errs.AddErr(err, i)
   111  			}
   112  		}
   113  		return errs.Err()
   114  	}
   115  
   116  	reader, ok := r.(CanNextReader)
   117  	if ok {
   118  		return t.tsfm.DecodeFrom(ctx, reader.NextReader(), v)
   119  	}
   120  	return t.tsfm.DecodeFrom(ctx, r, v)
   121  }
   122  
   123  type CanNextWriter interface {
   124  	NextWriter() io.Writer
   125  }
   126  
   127  type CanNextReader interface {
   128  	NextReader() io.Reader
   129  }