Skip to content

Instantly share code, notes, and snippets.

@Learath2
Created May 20, 2024 15:59
Show Gist options
  • Save Learath2/5902f1107b7a9069a2c8e5abed70ebe0 to your computer and use it in GitHub Desktop.
Save Learath2/5902f1107b7a9069a2c8e5abed70ebe0 to your computer and use it in GitHub Desktop.
func HookOpaqueTypeToFromMap(from reflect.Value, to reflect.Value) (v interface{}, err error) {
v = from.Interface()
anonMapType := reflect.TypeOf(map[string]interface{}{})
// Passthrough if we are not mapping to/from map[string]interface{}
if (to.Type() != anonMapType && from.Type() != anonMapType) || to.Type() == from.Type() {
return
}
otherVal, otherType := from, from.Type()
if to.Type() != anonMapType { //Encode
otherVal, otherType = to, to.Type()
}
// Get rid of indirection
if otherType.Kind() == reflect.Pointer {
otherType = otherType.Elem()
}
if otherType.Kind() != reflect.Struct {
return
}
exportedFields := 0
for i := 0; i < otherType.NumField(); i++ {
f := otherType.Field(i)
if f.PkgPath == "" {
exportedFields++
}
}
// Type not opaque struct
if exportedFields != 0 {
return
}
anonMapKey := "EncGOB"
if from.Type() != anonMapType { //Encode
var encoded interface{}
if m := otherVal.MethodByName("GobEncode"); !m.IsZero() {
res := m.Call([]reflect.Value{})
if res[1].IsNil() {
encoded = res[0].Interface()
}
}
return map[string]interface{}{"EncGOB": encoded}, nil
} else { //Decode
t := from.MapIndex(reflect.ValueOf(anonMapKey))
if t.IsZero() {
return
}
dst := reflect.New(otherType)
if m := dst.MethodByName("GobDecode"); !m.IsZero() {
res := m.Call([]reflect.Value{t.Elem()})
if !res[0].IsNil() {
return nil, res[0].Interface().(error)
}
}
return dst.Interface(), nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment