func getFieldByNameInner(t reflect.Type, name string) (reflect.StructField, bool) { nameArray := Explode(name, ".") if len(nameArray) == 0 { return reflect.StructField{}, false } var isExist bool var resultStruct reflect.StructField resultIndex := []int{} for _, singleName := range nameArray { resultStruct, isExist = t.FieldByName(singleName) if !isExist { return reflect.StructField{}, false } resultIndex = append(resultIndex, resultStruct.Index...) t = resultStruct.Type } resultStruct.Index = resultIndex return resultStruct, true }
//Returns the field or fields needed to fully write the struct's field func compileField(sf reflect.StructField, t reflect.Type, ind []int) []field { temp := sf.Index[0] sf.Index = make([]int, len(ind)+1) copy(sf.Index, ind) sf.Index[len(ind)] = temp f := field{sField: sf} cond := sf.Tag.Get("if") if len(cond) > 0 { var args [3]string pos := strings.Index(cond, ",") args[0] = cond[:pos] cond = cond[pos+1:] pos = strings.Index(cond, ",") args[1] = cond[:pos] args[2] = cond[pos+1:] checkField, ok := t.FieldByName(args[0]) if !ok { panic(fmt.Errorf("Unknown field: %s", args[0])) } in := make([]int, len(checkField.Index)+len(ind)) copy(in, ind) copy(in[len(ind):], checkField.Index) valsStr := strings.Split(args[2], "|") vals := make([]int64, len(valsStr)) for i := range vals { vals[i], _ = strconv.ParseInt(valsStr[i], 10, 64) } switch args[1] { case "!=": f.condition = func(root reflect.Value) bool { val := root.FieldByIndex(in).Int() for _, v := range vals { if v != val { return true } } return false } case "==": f.condition = func(root reflect.Value) bool { val := root.FieldByIndex(ind).Int() for _, v := range vals { if v == val { return true } } return false } } } else { f.condition = condAlways } switch sf.Type.Kind() { case reflect.Bool: f.write = encodeBool f.read = decodeBool case reflect.Int8: f.write = encodeInt8 f.read = decodeInt8 case reflect.Uint8: f.write = encodeUint8 f.read = decodeUint8 case reflect.Int16: f.write = encodeInt16 f.read = decodeInt16 case reflect.Uint16: f.write = encodeUint16 f.read = decodeUint16 case reflect.Int32: f.write = encodeInt32 f.read = decodeInt32 case reflect.Int64: f.write = encodeInt64 f.read = decodeInt64 case reflect.Float32: f.write = encodeFloat32 f.read = decodeFloat32 case reflect.Float64: f.write = encodeFloat64 f.read = decodeFloat64 case reflect.String: f.write = encodeString f.read = decodeString case reflect.Slice: e := sf.Type.Elem() f.write, f.read = getSliceCoders(e, sf) case reflect.Map: if sf.Tag.Get("metadata") == "true" { f.write = encodeMetadata f.read = decodeMetadata } else { panic("Maps NYI") } case reflect.Struct: return compileStruct(sf.Type, sf.Index) case reflect.Int: //VarInt f.write = encodeVarInt f.read = decodeVarInt default: panic(fmt.Errorf("Unhandled type %s for %s", sf.Type.Kind().String(), sf.Name)) } if f.write == nil { panic(fmt.Errorf("Missing write for type %s", sf.Type.Kind())) } if f.read == nil { panic(fmt.Errorf("Missing read for type %s", sf.Type.Kind())) } return []field{f} }