github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/conf/section_config/section_config_encoder.go (about)

     1  package section_config
     2  
     3  import (
     4  	"bytes"
     5  	"go/ast"
     6  	"os"
     7  	"reflect"
     8  
     9  	"github.com/machinefi/w3bstream/pkg/depends/base/types"
    10  	"github.com/machinefi/w3bstream/pkg/depends/x/reflectx"
    11  	"github.com/machinefi/w3bstream/pkg/depends/x/textx"
    12  )
    13  
    14  type Encoder struct {
    15  	Sep    byte
    16  	Values map[string]string
    17  }
    18  
    19  func NewEncoder(sep byte) *Encoder { return &Encoder{Sep: sep} }
    20  
    21  func (e *Encoder) Marshal(c SectionConfig) ([]byte, error) {
    22  	rv := reflectx.Indirect(reflect.ValueOf(c))
    23  
    24  	if rv.Kind() != reflect.Struct {
    25  		panic("input value should be a struct")
    26  	}
    27  
    28  	buf := bytes.NewBuffer(nil)
    29  	buf.WriteString(c.GetSection().String())
    30  	buf.WriteRune('\n')
    31  
    32  	if err := e.scan(rv, buf); err != nil {
    33  		return nil, err
    34  	}
    35  	return buf.Bytes(), nil
    36  }
    37  
    38  func (e *Encoder) MarshalToFile(c SectionConfig, path string) error {
    39  	data, err := e.Marshal(c)
    40  	if err != nil {
    41  		return err
    42  	}
    43  	return os.WriteFile(path, data, os.ModePerm)
    44  }
    45  
    46  func (e *Encoder) scan(rv reflect.Value, buf *bytes.Buffer) error {
    47  	kind := rv.Kind()
    48  
    49  	switch kind {
    50  	case reflect.Ptr:
    51  		if rv.IsNil() {
    52  			return nil
    53  		}
    54  		return e.scan(rv.Elem(), buf)
    55  	case reflect.Struct:
    56  		rt := rv.Type()
    57  		for i := 0; i < rv.NumField(); i++ {
    58  			ft, fv := rt.Field(i), rv.Field(i)
    59  			if !ast.IsExported(ft.Name) {
    60  				continue
    61  			}
    62  			if ft.Anonymous {
    63  				if err := e.scan(fv, buf); err != nil {
    64  					return err
    65  				}
    66  			}
    67  			tag, ok := ft.Tag.Lookup("name")
    68  			if !ok {
    69  				continue
    70  			}
    71  			key, _ := reflectx.TagValueAndFlags(tag)
    72  			var (
    73  				val []byte
    74  				err error
    75  			)
    76  			if v, ok := fv.Interface().(types.TextMarshaler); ok {
    77  				val, err = v.MarshalText()
    78  			} else {
    79  				val, err = textx.MarshalText(fv.Interface())
    80  			}
    81  			if err != nil {
    82  				return err
    83  			}
    84  			buf.Write([]byte(key))
    85  			buf.WriteByte(e.Sep)
    86  			buf.Write(val)
    87  			buf.WriteByte('\n')
    88  		}
    89  	default:
    90  		// skip
    91  	}
    92  	return nil
    93  }