goprotobuf: update for new Set semantics for reflect.Value.
R=rsc
CC=dsymonds, golang-dev
http://codereview.appspot.com/4432051
diff --git a/proto/extensions.go b/proto/extensions.go
index aec2f2d..53da04f 100644
--- a/proto/extensions.go
+++ b/proto/extensions.go
@@ -169,9 +169,24 @@
p := NewBuffer(nil)
v := reflect.NewValue(value)
- if err := props.enc(p, props, v.UnsafeAddr()); err != nil {
+ if err := props.enc(p, props, unsafeAddr(v)); err != nil {
return err
}
pb.ExtensionMap()[extension.Field] = p.buf
return nil
}
+
+// SetExtension assumes it can call UnsafeAddr on any Value
+// in order to get a pointer it can copy data from.
+// Values that have just been created and do not point
+// into existing structs or slices cannot be addressed,
+// so simulate it by returning a pointer to a copy.
+// Each call allocates once.
+func unsafeAddr(v reflect.Value) uintptr {
+ if v.CanAddr() {
+ return v.UnsafeAddr()
+ }
+ x := reflect.New(v.Type()).Elem()
+ x.Set(v)
+ return x.UnsafeAddr()
+}
diff --git a/proto/text_parser.go b/proto/text_parser.go
index ed1cd5c..9463afc 100644
--- a/proto/text_parser.go
+++ b/proto/text_parser.go
@@ -412,7 +412,7 @@
case reflect.Ptr:
// A basic field (indirected through pointer), or a repeated message/group
p.back()
- fv.Set(reflect.Zero(fv.Type().Elem()).Addr())
+ fv.Set(reflect.New(fv.Type().Elem()))
return p.readAny(fv.Elem(), props)
case reflect.String:
if tok.value[0] == '"' {