github.com/abemedia/appcast@v0.4.0/integrations/apt/deb/encode.go (about)

     1  package deb
     2  
     3  import (
     4  	"bytes"
     5  	"encoding"
     6  	"encoding/hex"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"reflect"
    11  	"strconv"
    12  	"sync"
    13  	"time"
    14  )
    15  
    16  var encoders sync.Map //nolint:gochecknoglobals
    17  
    18  type encoder func(io.Writer, reflect.Value) error
    19  
    20  func Marshal(v any) ([]byte, error) {
    21  	buf := &bytes.Buffer{}
    22  	if err := NewEncoder(buf).Encode(v); err != nil {
    23  		return nil, err
    24  	}
    25  	return buf.Bytes(), nil
    26  }
    27  
    28  type Encoder struct {
    29  	w io.Writer
    30  }
    31  
    32  func NewEncoder(w io.Writer) *Encoder {
    33  	return &Encoder{w}
    34  }
    35  
    36  func (e *Encoder) Encode(v any) error {
    37  	if v == nil {
    38  		return errors.New("unsupported type: nil")
    39  	}
    40  
    41  	val := reflect.ValueOf(v)
    42  	typ := val.Type()
    43  
    44  	if enc, ok := encoders.Load(typ); ok {
    45  		return enc.(encoder)(e.w, val) //nolint:forcetypeassert
    46  	}
    47  
    48  	enc, err := newEncoder(typ)
    49  	if err != nil {
    50  		return err
    51  	}
    52  	encoders.Store(typ, enc)
    53  	return enc(e.w, val)
    54  }
    55  
    56  //nolint:gochecknoglobals
    57  var (
    58  	stringerType  = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
    59  	marshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
    60  )
    61  
    62  func newEncoder(typ reflect.Type) (encoder, error) {
    63  	switch {
    64  	case typ == dateType:
    65  		return newDateEncoder(typ)
    66  	case typ.Implements(marshalerType):
    67  		return newMarshalerEncoder(typ)
    68  	case typ.Implements(stringerType):
    69  		return newStringerEncoder(typ)
    70  	}
    71  
    72  	switch typ.Kind() {
    73  	case reflect.Ptr:
    74  		return newPtrEncoder(typ)
    75  	case reflect.Slice:
    76  		return newSliceEncoder(typ)
    77  	case reflect.Struct:
    78  		return newStructEncoder(typ)
    79  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    80  		return newIntEncoder(typ)
    81  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
    82  		return newUintEncoder(typ)
    83  	case reflect.Float32, reflect.Float64:
    84  		return newFloatEncoder(typ)
    85  	case reflect.String:
    86  		return newStringEncoder(typ)
    87  	case reflect.Array:
    88  		if typ.Elem().Kind() == reflect.Uint8 {
    89  			return newByteArrayEncoder(typ)
    90  		}
    91  	}
    92  	return nil, fmt.Errorf("unsupported type: %s", typ)
    93  }
    94  
    95  func newStringerEncoder(typ reflect.Type) (encoder, error) {
    96  	ptr := typ.Kind() == reflect.Pointer
    97  	return func(w io.Writer, v reflect.Value) error {
    98  		if ptr && v.IsNil() {
    99  			return nil
   100  		}
   101  		s := v.Interface().(fmt.Stringer).String() //nolint:forcetypeassert
   102  		if len(s) == 0 {
   103  			return nil
   104  		}
   105  		return encodeText(w, atob(s))
   106  	}, nil
   107  }
   108  
   109  func newMarshalerEncoder(typ reflect.Type) (encoder, error) {
   110  	ptr := typ.Kind() == reflect.Pointer
   111  	return func(w io.Writer, v reflect.Value) error {
   112  		if ptr && v.IsNil() {
   113  			return nil
   114  		}
   115  		b, err := v.Interface().(encoding.TextMarshaler).MarshalText()
   116  		if err != nil {
   117  			return err
   118  		}
   119  		if len(b) == 0 {
   120  			return nil
   121  		}
   122  		return encodeText(w, b)
   123  	}, nil
   124  }
   125  
   126  func newPtrEncoder(typ reflect.Type) (encoder, error) {
   127  	typ = typ.Elem()
   128  	enc, err := newEncoder(typ)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	return func(w io.Writer, v reflect.Value) error {
   134  		if v.IsNil() {
   135  			return nil
   136  		}
   137  		return enc(w, v.Elem())
   138  	}, nil
   139  }
   140  
   141  func newSliceEncoder(typ reflect.Type) (encoder, error) {
   142  	enc, err := newEncoder(typ.Elem())
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  
   147  	return func(w io.Writer, v reflect.Value) error {
   148  		for i := 0; i < v.Len(); i++ {
   149  			if i != 0 {
   150  				if _, err := w.Write(nl); err != nil {
   151  					return err
   152  				}
   153  			}
   154  			if err := enc(w, v.Index(i)); err != nil {
   155  				return err
   156  			}
   157  		}
   158  
   159  		return nil
   160  	}, nil
   161  }
   162  
   163  //nolint:gocognit
   164  func newStructEncoder(typ reflect.Type) (encoder, error) {
   165  	encoders := []func(buf *bytes.Buffer, w io.Writer, v reflect.Value) error{}
   166  
   167  	for i := 0; i < typ.NumField(); i++ {
   168  		i := i
   169  		field := typ.Field(i)
   170  
   171  		n := getFieldName(field)
   172  		if n == "" {
   173  			continue
   174  		}
   175  		name := atob(n)
   176  
   177  		enc, err := newEncoder(field.Type)
   178  		if err != nil {
   179  			return nil, err
   180  		}
   181  		encoders = append(encoders, func(buf *bytes.Buffer, w io.Writer, v reflect.Value) error {
   182  			if err := enc(buf, v.Field(i)); err != nil {
   183  				return err
   184  			}
   185  			if buf.Len() == 0 {
   186  				return nil
   187  			}
   188  			if _, err = w.Write(name); err != nil {
   189  				return err
   190  			}
   191  			if _, err = w.Write(colon); err != nil {
   192  				return err
   193  			}
   194  
   195  			// Only write space after colon if content doesn't start with line break.
   196  			if c, _ := buf.ReadByte(); c != '\n' {
   197  				if _, err = w.Write(space); err != nil {
   198  					return err
   199  				}
   200  			}
   201  			_ = buf.UnreadByte()
   202  
   203  			if _, err = io.Copy(w, buf); err != nil {
   204  				return err
   205  			}
   206  			_, err = w.Write(nl)
   207  			return err
   208  		})
   209  	}
   210  
   211  	return func(w io.Writer, v reflect.Value) error {
   212  		buf := bufPool.Get().(*bytes.Buffer) //nolint:forcetypeassert
   213  		defer bufPool.Put(buf)
   214  		for _, enc := range encoders {
   215  			buf.Reset()
   216  			if err := enc(buf, w, v); err != nil {
   217  				return err
   218  			}
   219  		}
   220  		return nil
   221  	}, nil
   222  }
   223  
   224  func newDateEncoder(reflect.Type) (encoder, error) {
   225  	return func(w io.Writer, v reflect.Value) error {
   226  		t := v.Interface().(time.Time) //nolint:forcetypeassert
   227  		if t.IsZero() {
   228  			return nil
   229  		}
   230  		_, err := w.Write(atob(t.Format(time.RFC1123)))
   231  		return err
   232  	}, nil
   233  }
   234  
   235  func newIntEncoder(reflect.Type) (encoder, error) {
   236  	return func(w io.Writer, v reflect.Value) error {
   237  		i := v.Int()
   238  		if i == 0 {
   239  			return nil
   240  		}
   241  		_, err := w.Write(atob(strconv.FormatInt(i, 10)))
   242  		return err
   243  	}, nil
   244  }
   245  
   246  func newUintEncoder(reflect.Type) (encoder, error) {
   247  	return func(w io.Writer, v reflect.Value) error {
   248  		i := v.Uint()
   249  		if i == 0 {
   250  			return nil
   251  		}
   252  		_, err := w.Write(atob(strconv.FormatUint(i, 10)))
   253  		return err
   254  	}, nil
   255  }
   256  
   257  func newFloatEncoder(typ reflect.Type) (encoder, error) {
   258  	bits := typ.Bits()
   259  	return func(w io.Writer, v reflect.Value) error {
   260  		f := v.Float()
   261  		if f == 0 {
   262  			return nil
   263  		}
   264  		_, err := w.Write(atob(strconv.FormatFloat(f, 'f', -1, bits)))
   265  		return err
   266  	}, nil
   267  }
   268  
   269  func newByteArrayEncoder(typ reflect.Type) (encoder, error) {
   270  	size := typ.Len()
   271  	return func(w io.Writer, v reflect.Value) error {
   272  		var isNonZero bool
   273  		b := make([]byte, size)
   274  		for i := 0; i < size; i++ {
   275  			if n := v.Index(i).Uint(); n > 0 {
   276  				b[i] = byte(n)
   277  				isNonZero = true
   278  			}
   279  		}
   280  		if !isNonZero {
   281  			return nil
   282  		}
   283  		_, err := hex.NewEncoder(w).Write(b)
   284  		return err
   285  	}, nil
   286  }
   287  
   288  func newStringEncoder(reflect.Type) (encoder, error) {
   289  	return func(w io.Writer, v reflect.Value) error {
   290  		return encodeText(w, atob(v.String()))
   291  	}, nil
   292  }
   293  
   294  func encodeText(w io.Writer, in []byte) error {
   295  	if i := bytes.IndexByte(in, '\n'); i == -1 {
   296  		_, err := w.Write(in)
   297  		return err
   298  	}
   299  
   300  	out := make([]byte, 0, len(in)+bytes.Count(in, nl)*2)
   301  	for i, c := range in {
   302  		if c == '\n' {
   303  			var last byte
   304  			for j := i - 1; j > 0; j-- {
   305  				if l := in[j]; l != '\n' && l != '\r' {
   306  					break
   307  				}
   308  				last = in[j]
   309  			}
   310  			if last == '\n' {
   311  				out = append(out, '.')
   312  			}
   313  			out = append(out, '\n', ' ')
   314  		} else {
   315  			out = append(out, c)
   316  		}
   317  	}
   318  
   319  	_, err := w.Write(out)
   320  	return err
   321  }