summaryrefslogblamecommitdiff
path: root/serial.go
blob: 59a3118c772a916fb33dba819c0fbb9c9dc663ba (plain) (tree)





























































































                                                                                    
package serial

import (
	"io"
	"reflect"
	"strconv"
	"strings"
	"sync"
)

type Encoder struct {
	w      io.Writer
	wg     sync.WaitGroup
	groups []string
}

func (e *Encoder) Encode(entity interface{}) error {
	t := reflect.TypeOf(entity)
	v := reflect.ValueOf(entity)
	if err := e.encodeField(t, v, e.w); err != nil {
		return err
	}
	return nil
}
func (e *Encoder) encodeAny(entity interface{}, w io.Writer) error {
	t := reflect.TypeOf(entity)
	v := reflect.ValueOf(entity)
	first := true
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		fv := v.Field(i)
		if gr, ok := f.Tag.Lookup("group"); ok {
			groups := strings.Split(gr, ",")
			name := f.Name
			if tname, ok := f.Tag.Lookup("json"); ok {
				name = tname
			}
			if name != "-" && e.intersect(groups, e.groups) {
				if !first {
					w.Write([]byte(`,`))
				}
				w.Write([]byte(`"` + name + `":`))
				e.encodeField(f.Type, fv, w)
				first = false
			}
		}
	}
	return nil
}

func (e *Encoder) intersect(a []string, b []string) bool {
	for _, sa := range a {
		for _, sb := range b {
			if sa == sb {
				return true
			}
		}
	}
	return false
}

func (e *Encoder) encodeField(ft reflect.Type, v reflect.Value, w io.Writer) error {
	switch ft.Kind() {
	case reflect.Struct:
		w.Write([]byte("{"))
		if err := e.encodeAny(v.Interface(), w); err != nil {
			return err
		}
		w.Write([]byte("}"))
	case reflect.String:
		w.Write([]byte(`"` + v.String() + `"`))
	case reflect.Bool:
		if v.Bool() {
			w.Write([]byte("true"))
		} else {
			w.Write([]byte("false"))
		}
	case reflect.Int, reflect.Int32, reflect.Int64:
		w.Write([]byte(strconv.Itoa(int(v.Int()))))
	case reflect.Float32, reflect.Float64:
		w.Write([]byte(strconv.FormatFloat(v.Float(), 'f', -1, 64)))

	}
	return nil
}

func (e *Encoder) AddGroup(group string) *Encoder {
	e.groups = append(e.groups, group)
	return e
}

func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{w: w, groups: []string{}}
}