package main import ( "fmt" "io" "os" "reflect" "strconv" "strings" "sync" ) type IJceStruct interface{} const head = "// Code generated by structs_parser; DO NOT EDIT.\npackage jce\n" func Main_() { w, err := os.Create("%s") if err != nil { panic(err) } w.WriteString(head) // structs_parser: fill area err = w.Close() if err != nil { panic(err) } } func writeObject(w io.Writer, v reflect.Value, tag byte, name string) { k := v.Kind() if k == reflect.Map { switch v.Interface().(type) { case map[string]string: w.Write([]byte(fmt.Sprintf("\tw.writeMapStrStr(pkt.%s, %d)\n", name, tag))) case map[string][]byte: w.Write([]byte(fmt.Sprintf("\tw.writeMapStrBytes(pkt.%s, %d)\n", name, tag))) case map[string]map[string][]byte: w.Write([]byte(fmt.Sprintf("\tw.writeMapStrMapStrBytes(pkt.%s, %d)\n", name, tag))) default: w.Write([]byte(fmt.Sprintf("\tw.writeMap(pkt.%s, %d)\n", name, tag))) } return } if k == reflect.Slice { switch v.Interface().(type) { case []byte: w.Write([]byte(fmt.Sprintf("\tw.WriteBytes(pkt.%s, %d)\n", name, tag))) case []int64: w.Write([]byte(fmt.Sprintf("\tw.WriteInt64Slice(pkt.%s, %d)\n", name, tag))) case [][]byte: w.Write([]byte(fmt.Sprintf("\tw.WriteBytesSlice(pkt.%s, %d)\n", name, tag))) default: writeJceStructSlice(w, tag, name) } return } switch k { case reflect.Uint8, reflect.Int8: w.Write([]byte(fmt.Sprintf("\tw.WriteByte(pkt.%s, %d)\n", name, tag))) case reflect.Uint16, reflect.Int16: w.Write([]byte(fmt.Sprintf("\tw.WriteInt16(pkt.%s, %d)\n", name, tag))) case reflect.Uint32, reflect.Int32: w.Write([]byte(fmt.Sprintf("\tw.WriteInt32(pkt.%s, %d)\n", name, tag))) case reflect.Uint64, reflect.Int64: w.Write([]byte(fmt.Sprintf("\tw.WriteInt64(pkt.%s, %d)\n", name, tag))) case reflect.Int, reflect.Uint: w.Write([]byte(fmt.Sprintf("\tw.WriteInt64(int64(pkt.%s), %d)\n", name, tag))) case reflect.String: w.Write([]byte(fmt.Sprintf("\tw.WriteString(pkt.%s, %d)\n", name, tag))) default: switch v.Interface().(type) { case float32: w.Write([]byte(fmt.Sprintf("\tw.WriteFloat32(pkt.%s, %d)\n", name, tag))) case float64: w.Write([]byte(fmt.Sprintf("\tw.WriteFloat64(pkt.%s, %d)\n", name, tag))) case IJceStruct: w.Write([]byte(fmt.Sprintf("\tw.writeHead(10, %d)\n", tag))) w.Write([]byte(fmt.Sprintf("\tw.buf.Write(pkt.%s.ToBytes())\n", name))) w.Write([]byte("\tw.writeHead(11, 0)\n")) } } } type decoder struct { index int id int name string } var decoderCache = sync.Map{} // writeJceStructRaw 写入 Jce 结构体 func writeJceStructRaw(w io.Writer, s interface{}) { t := reflect.TypeOf(s) if t.Kind() != reflect.Ptr { return } t = t.Elem() v := reflect.ValueOf(s).Elem() var jceDec []decoder dec, ok := decoderCache.Load(t) if ok { // 从缓存中加载 jceDec = dec.([]decoder) } else { // 初次反射 jceDec = make([]decoder, 0, t.NumField()) for i := 0; i < t.NumField(); i++ { field := t.Field(i) strId := field.Tag.Get("jceId") if strId == "" { continue } id, err := strconv.Atoi(strId) if err != nil { continue } jceDec = append(jceDec, decoder{ index: i, id: id, name: field.Name, }) } decoderCache.Store(t, jceDec) // 存入缓存 } for _, dec := range jceDec { obj := v.Field(dec.index) writeObject(w, obj, byte(dec.id), dec.name) } } func writeJceStructSlice(w io.Writer, tag byte, name string) { w.Write([]byte(fmt.Sprintf("\tw.writeHead(9, %d)\n", tag))) w.Write([]byte(fmt.Sprintf("\tif len(pkt.%s) == 0 {\n", name))) w.Write([]byte("\t\tw.writeHead(12, 0) // w.WriteInt32(0, 0)\n")) w.Write([]byte("\t} else {\n")) w.Write([]byte(fmt.Sprintf("\t\tw.WriteInt32(int32(len(pkt.%s)), 0)\n", name))) w.Write([]byte(fmt.Sprintf("\t\tfor _, i := range pkt.%s {\n", name))) w.Write([]byte("\t\t\tw.buf.Write(i.ToBytes())\n")) w.Write([]byte("\t\t}\n")) w.Write([]byte("\t}\n")) } func WriteJceStruct(w io.Writer, s IJceStruct) { w.Write([]byte(fmt.Sprintf("\nfunc (pkt %s) ToBytes() []byte {\n", strings.ReplaceAll(reflect.TypeOf(s).String(), "main.", "")))) w.Write([]byte("\tw := NewJceWriter()\n")) writeJceStructRaw(w, s) w.Write([]byte("\treturn w.Bytes()\n")) w.Write([]byte("}\n")) }