diff options
-rw-r--r-- | serial.go | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/serial.go b/serial.go new file mode 100644 index 0000000..59a3118 --- /dev/null +++ b/serial.go @@ -0,0 +1,94 @@ +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{}} +} |