Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
ce3ba126
Commit
ce3ba126
authored
Aug 14, 2013
by
Russ Cox
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
encoding/gob: support new generic interfaces in package encoding
R=r CC=golang-dev
https://golang.org/cl/12681044
parent
48b90bbc
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
269 additions
and
76 deletions
+269
-76
src/pkg/encoding/gob/debug.go
src/pkg/encoding/gob/debug.go
+10
-0
src/pkg/encoding/gob/decode.go
src/pkg/encoding/gob/decode.go
+27
-13
src/pkg/encoding/gob/doc.go
src/pkg/encoding/gob/doc.go
+22
-13
src/pkg/encoding/gob/encode.go
src/pkg/encoding/gob/encode.go
+20
-9
src/pkg/encoding/gob/encoder.go
src/pkg/encoding/gob/encoder.go
+2
-2
src/pkg/encoding/gob/gobencdec_test.go
src/pkg/encoding/gob/gobencdec_test.go
+126
-18
src/pkg/encoding/gob/type.go
src/pkg/encoding/gob/type.go
+62
-21
No files found.
src/pkg/encoding/gob/debug.go
View file @
ce3ba126
...
...
@@ -415,6 +415,16 @@ func (deb *debugger) typeDefinition(indent tab, id typeId) {
deb
.
delta
(
1
)
com
:=
deb
.
common
()
wire
.
GobEncoderT
=
&
gobEncoderType
{
com
}
case
5
:
// BinaryMarshaler type, one field of {{Common}}
// Field number 0 is CommonType
deb
.
delta
(
1
)
com
:=
deb
.
common
()
wire
.
BinaryMarshalerT
=
&
gobEncoderType
{
com
}
case
6
:
// TextMarshaler type, one field of {{Common}}
// Field number 0 is CommonType
deb
.
delta
(
1
)
com
:=
deb
.
common
()
wire
.
TextMarshalerT
=
&
gobEncoderType
{
com
}
default
:
errorf
(
"bad field in type %d"
,
fieldNum
)
}
...
...
src/pkg/encoding/gob/decode.go
View file @
ce3ba126
...
...
@@ -9,6 +9,7 @@ package gob
import
(
"bytes"
"encoding"
"errors"
"io"
"math"
...
...
@@ -767,15 +768,22 @@ func (dec *Decoder) ignoreInterface(state *decoderState) {
// decodeGobDecoder decodes something implementing the GobDecoder interface.
// The data is encoded as a byte slice.
func
(
dec
*
Decoder
)
decodeGobDecoder
(
state
*
decoderState
,
v
reflect
.
Value
)
{
func
(
dec
*
Decoder
)
decodeGobDecoder
(
ut
*
userTypeInfo
,
state
*
decoderState
,
v
reflect
.
Value
)
{
// Read the bytes for the value.
b
:=
make
([]
byte
,
state
.
decodeUint
())
_
,
err
:=
state
.
b
.
Read
(
b
)
if
err
!=
nil
{
error_
(
err
)
}
// We know it's a GobDecoder, so just call the method directly.
err
=
v
.
Interface
()
.
(
GobDecoder
)
.
GobDecode
(
b
)
// We know it's one of these.
switch
ut
.
externalDec
{
case
xGob
:
err
=
v
.
Interface
()
.
(
GobDecoder
)
.
GobDecode
(
b
)
case
xBinary
:
err
=
v
.
Interface
()
.
(
encoding
.
BinaryUnmarshaler
)
.
UnmarshalBinary
(
b
)
case
xText
:
err
=
v
.
Interface
()
.
(
encoding
.
TextUnmarshaler
)
.
UnmarshalText
(
b
)
}
if
err
!=
nil
{
error_
(
err
)
}
...
...
@@ -825,9 +833,10 @@ var decIgnoreOpMap = map[typeId]decOp{
func
(
dec
*
Decoder
)
decOpFor
(
wireId
typeId
,
rt
reflect
.
Type
,
name
string
,
inProgress
map
[
reflect
.
Type
]
*
decOp
)
(
*
decOp
,
int
)
{
ut
:=
userType
(
rt
)
// If the type implements GobEncoder, we handle it without further processing.
if
ut
.
isGobDecoder
{
if
ut
.
externalDec
!=
0
{
return
dec
.
gobDecodeOpFor
(
ut
)
}
// If this type is already in progress, it's a recursive type (e.g. map[string]*T).
// Return the pointer to the op we're already building.
if
opPtr
:=
inProgress
[
rt
];
opPtr
!=
nil
{
...
...
@@ -954,7 +963,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
state
.
dec
.
ignoreStruct
(
*
enginePtr
)
}
case
wire
.
GobEncoderT
!=
nil
:
case
wire
.
GobEncoderT
!=
nil
,
wire
.
BinaryMarshalerT
!=
nil
,
wire
.
TextMarshalerT
!=
nil
:
op
=
func
(
i
*
decInstr
,
state
*
decoderState
,
p
unsafe
.
Pointer
)
{
state
.
dec
.
ignoreGobDecoder
(
state
)
}
...
...
@@ -993,7 +1002,7 @@ func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
}
else
{
v
=
reflect
.
NewAt
(
rcvrType
,
p
)
.
Elem
()
}
state
.
dec
.
decodeGobDecoder
(
state
,
v
)
state
.
dec
.
decodeGobDecoder
(
ut
,
state
,
v
)
}
return
&
op
,
int
(
ut
.
indir
)
...
...
@@ -1010,12 +1019,18 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId, inProgress map[re
inProgress
[
fr
]
=
fw
ut
:=
userType
(
fr
)
wire
,
ok
:=
dec
.
wireType
[
fw
]
// If fr is a GobDecoder, the wire type must be GobEncoder.
// And if fr is not a GobDecoder, the wire type must not be either.
if
ut
.
isGobDecoder
!=
(
ok
&&
wire
.
GobEncoderT
!=
nil
)
{
// the parentheses look odd but are correct.
// If wire was encoded with an encoding method, fr must have that method.
// And if not, it must not.
// At most one of the booleans in ut is set.
// We could possibly relax this constraint in the future in order to
// choose the decoding method using the data in the wireType.
// The parentheses look odd but are correct.
if
(
ut
.
externalDec
==
xGob
)
!=
(
ok
&&
wire
.
GobEncoderT
!=
nil
)
||
(
ut
.
externalDec
==
xBinary
)
!=
(
ok
&&
wire
.
BinaryMarshalerT
!=
nil
)
||
(
ut
.
externalDec
==
xText
)
!=
(
ok
&&
wire
.
TextMarshalerT
!=
nil
)
{
return
false
}
if
ut
.
isGobDecoder
{
// This test trumps all others.
if
ut
.
externalDec
!=
0
{
// This test trumps all others.
return
true
}
switch
t
:=
ut
.
base
;
t
.
Kind
()
{
...
...
@@ -1114,8 +1129,7 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err
func
(
dec
*
Decoder
)
compileDec
(
remoteId
typeId
,
ut
*
userTypeInfo
)
(
engine
*
decEngine
,
err
error
)
{
rt
:=
ut
.
base
srt
:=
rt
if
srt
.
Kind
()
!=
reflect
.
Struct
||
ut
.
isGobDecoder
{
if
srt
.
Kind
()
!=
reflect
.
Struct
||
ut
.
externalDec
!=
0
{
return
dec
.
compileSingle
(
remoteId
,
ut
)
}
var
wireStruct
*
structType
...
...
@@ -1223,7 +1237,7 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
return
}
engine
:=
*
enginePtr
if
st
:=
base
;
st
.
Kind
()
==
reflect
.
Struct
&&
!
ut
.
isGobDecoder
{
if
st
:=
base
;
st
.
Kind
()
==
reflect
.
Struct
&&
ut
.
externalDec
==
0
{
if
engine
.
numInstr
==
0
&&
st
.
NumField
()
>
0
&&
len
(
dec
.
wireType
[
wireId
]
.
StructT
.
Field
)
>
0
{
name
:=
base
.
Name
()
errorf
(
"type mismatch: no fields matched compiling decoder for %s"
,
name
)
...
...
src/pkg/encoding/gob/doc.go
View file @
ce3ba126
...
...
@@ -67,19 +67,28 @@ point values may be received into any floating point variable. However,
the destination variable must be able to represent the value or the decode
operation will fail.
Structs, arrays and slices are also supported. Structs encode and
decode only exported fields. Strings and arrays of bytes are supported
with a special, efficient representation (see below). When a slice
is decoded, if the existing slice has capacity the slice will be
extended in place; if not, a new array is allocated. Regardless,
the length of the resulting slice reports the number of elements
decoded.
Functions and channels cannot be sent in a gob. Attempting
to encode a value that contains one will fail.
The rest of this comment documents the encoding, details that are not important
for most users. Details are presented bottom-up.
Structs, arrays and slices are also supported. Structs encode and decode only
exported fields. Strings and arrays of bytes are supported with a special,
efficient representation (see below). When a slice is decoded, if the existing
slice has capacity the slice will be extended in place; if not, a new array is
allocated. Regardless, the length of the resulting slice reports the number of
elements decoded.
Functions and channels cannot be sent in a gob. Attempting to encode a value
that contains one will fail.
Gob can encode a value of any type implementing the GobEncoder,
encoding.BinaryMarshaler, or encoding.TextMarshaler interfaces by calling the
corresponding method, in that order of preference.
Gob can decode a value of any type implementing the GobDecoder,
encoding.BinaryUnmarshaler, or encoding.TextUnmarshaler interfaces by calling
the corresponding method, again in that order of preference.
Encoding Details
This section documents the encoding, details that are not important for most
users. Details are presented bottom-up.
An unsigned integer is sent one of two ways. If it is less than 128, it is sent
as a byte with that value. Otherwise it is sent as a minimal-length big-endian
...
...
src/pkg/encoding/gob/encode.go
View file @
ce3ba126
...
...
@@ -6,6 +6,7 @@ package gob
import
(
"bytes"
"encoding"
"math"
"reflect"
"unsafe"
...
...
@@ -511,10 +512,20 @@ func isZero(val reflect.Value) bool {
// encGobEncoder encodes a value that implements the GobEncoder interface.
// The data is sent as a byte array.
func
(
enc
*
Encoder
)
encodeGobEncoder
(
b
*
bytes
.
Buffer
,
v
reflect
.
Value
)
{
func
(
enc
*
Encoder
)
encodeGobEncoder
(
b
*
bytes
.
Buffer
,
ut
*
userTypeInfo
,
v
reflect
.
Value
)
{
// TODO: should we catch panics from the called method?
// We know it's a GobEncoder, so just call the method directly.
data
,
err
:=
v
.
Interface
()
.
(
GobEncoder
)
.
GobEncode
()
var
data
[]
byte
var
err
error
// We know it's one of these.
switch
ut
.
externalEnc
{
case
xGob
:
data
,
err
=
v
.
Interface
()
.
(
GobEncoder
)
.
GobEncode
()
case
xBinary
:
data
,
err
=
v
.
Interface
()
.
(
encoding
.
BinaryMarshaler
)
.
MarshalBinary
()
case
xText
:
data
,
err
=
v
.
Interface
()
.
(
encoding
.
TextMarshaler
)
.
MarshalText
()
}
if
err
!=
nil
{
error_
(
err
)
}
...
...
@@ -550,7 +561,7 @@ var encOpTable = [...]encOp{
func
(
enc
*
Encoder
)
encOpFor
(
rt
reflect
.
Type
,
inProgress
map
[
reflect
.
Type
]
*
encOp
)
(
*
encOp
,
int
)
{
ut
:=
userType
(
rt
)
// If the type implements GobEncoder, we handle it without further processing.
if
ut
.
isGobEncoder
{
if
ut
.
externalEnc
!=
0
{
return
enc
.
gobEncodeOpFor
(
ut
)
}
// If this type is already in progress, it's a recursive type (e.g. map[string]*T).
...
...
@@ -661,7 +672,7 @@ func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
return
}
state
.
update
(
i
)
state
.
enc
.
encodeGobEncoder
(
state
.
b
,
v
)
state
.
enc
.
encodeGobEncoder
(
state
.
b
,
ut
,
v
)
}
return
&
op
,
int
(
ut
.
encIndir
)
// encIndir: op will get called with p == address of receiver.
}
...
...
@@ -672,10 +683,10 @@ func (enc *Encoder) compileEnc(ut *userTypeInfo) *encEngine {
engine
:=
new
(
encEngine
)
seen
:=
make
(
map
[
reflect
.
Type
]
*
encOp
)
rt
:=
ut
.
base
if
ut
.
isGobEncoder
{
if
ut
.
externalEnc
!=
0
{
rt
=
ut
.
user
}
if
!
ut
.
isGobEncoder
&&
if
ut
.
externalEnc
==
0
&&
srt
.
Kind
()
==
reflect
.
Struct
{
for
fieldNum
,
wireFieldNum
:=
0
,
0
;
fieldNum
<
srt
.
NumField
();
fieldNum
++
{
f
:=
srt
.
Field
(
fieldNum
)
...
...
@@ -736,13 +747,13 @@ func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInf
defer
catchError
(
&
enc
.
err
)
engine
:=
enc
.
lockAndGetEncEngine
(
ut
)
indir
:=
ut
.
indir
if
ut
.
isGobEncoder
{
if
ut
.
externalEnc
!=
0
{
indir
=
int
(
ut
.
encIndir
)
}
for
i
:=
0
;
i
<
indir
;
i
++
{
value
=
reflect
.
Indirect
(
value
)
}
if
!
ut
.
isGobEncoder
&&
value
.
Type
()
.
Kind
()
==
reflect
.
Struct
{
if
ut
.
externalEnc
==
0
&&
value
.
Type
()
.
Kind
()
==
reflect
.
Struct
{
enc
.
encodeStruct
(
b
,
engine
,
unsafeAddr
(
value
))
}
else
{
enc
.
encodeSingle
(
b
,
engine
,
unsafeAddr
(
value
))
...
...
src/pkg/encoding/gob/encoder.go
View file @
ce3ba126
...
...
@@ -135,7 +135,7 @@ func (enc *Encoder) sendActualType(w io.Writer, state *encoderState, ut *userTyp
// sendType sends the type info to the other side, if necessary.
func
(
enc
*
Encoder
)
sendType
(
w
io
.
Writer
,
state
*
encoderState
,
origt
reflect
.
Type
)
(
sent
bool
)
{
ut
:=
userType
(
origt
)
if
ut
.
isGobEncoder
{
if
ut
.
externalEnc
!=
0
{
// The rules are different: regardless of the underlying type's representation,
// we need to tell the other side that the base type is a GobEncoder.
return
enc
.
sendActualType
(
w
,
state
,
ut
,
ut
.
base
)
...
...
@@ -184,7 +184,7 @@ func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *use
// Make sure the type is known to the other side.
// First, have we already sent this type?
rt
:=
ut
.
base
if
ut
.
isGobEncoder
{
if
ut
.
externalEnc
!=
0
{
rt
=
ut
.
user
}
if
_
,
alreadySent
:=
enc
.
sent
[
rt
];
!
alreadySent
{
...
...
src/pkg/encoding/gob/gobencdec_test.go
View file @
ce3ba126
...
...
@@ -34,6 +34,14 @@ type Gobber int
type
ValueGobber
string
// encodes with a value, decodes with a pointer.
type
BinaryGobber
int
type
BinaryValueGobber
string
type
TextGobber
int
type
TextValueGobber
string
// The relevant methods
func
(
g
*
ByteStruct
)
GobEncode
()
([]
byte
,
error
)
{
...
...
@@ -101,6 +109,24 @@ func (g *Gobber) GobDecode(data []byte) error {
return
err
}
func
(
g
*
BinaryGobber
)
MarshalBinary
()
([]
byte
,
error
)
{
return
[]
byte
(
fmt
.
Sprintf
(
"VALUE=%d"
,
*
g
)),
nil
}
func
(
g
*
BinaryGobber
)
UnmarshalBinary
(
data
[]
byte
)
error
{
_
,
err
:=
fmt
.
Sscanf
(
string
(
data
),
"VALUE=%d"
,
(
*
int
)(
g
))
return
err
}
func
(
g
*
TextGobber
)
MarshalText
()
([]
byte
,
error
)
{
return
[]
byte
(
fmt
.
Sprintf
(
"VALUE=%d"
,
*
g
)),
nil
}
func
(
g
*
TextGobber
)
UnmarshalText
(
data
[]
byte
)
error
{
_
,
err
:=
fmt
.
Sscanf
(
string
(
data
),
"VALUE=%d"
,
(
*
int
)(
g
))
return
err
}
func
(
v
ValueGobber
)
GobEncode
()
([]
byte
,
error
)
{
return
[]
byte
(
fmt
.
Sprintf
(
"VALUE=%s"
,
v
)),
nil
}
...
...
@@ -110,6 +136,24 @@ func (v *ValueGobber) GobDecode(data []byte) error {
return
err
}
func
(
v
BinaryValueGobber
)
MarshalBinary
()
([]
byte
,
error
)
{
return
[]
byte
(
fmt
.
Sprintf
(
"VALUE=%s"
,
v
)),
nil
}
func
(
v
*
BinaryValueGobber
)
UnmarshalBinary
(
data
[]
byte
)
error
{
_
,
err
:=
fmt
.
Sscanf
(
string
(
data
),
"VALUE=%s"
,
(
*
string
)(
v
))
return
err
}
func
(
v
TextValueGobber
)
MarshalText
()
([]
byte
,
error
)
{
return
[]
byte
(
fmt
.
Sprintf
(
"VALUE=%s"
,
v
)),
nil
}
func
(
v
*
TextValueGobber
)
UnmarshalText
(
data
[]
byte
)
error
{
_
,
err
:=
fmt
.
Sscanf
(
string
(
data
),
"VALUE=%s"
,
(
*
string
)(
v
))
return
err
}
// Structs that include GobEncodable fields.
type
GobTest0
struct
{
...
...
@@ -130,28 +174,42 @@ type GobTest2 struct {
type
GobTest3
struct
{
X
int
// guarantee we have something in common with GobTest*
G
*
Gobber
B
*
BinaryGobber
T
*
TextGobber
}
type
GobTest4
struct
{
X
int
// guarantee we have something in common with GobTest*
V
ValueGobber
X
int
// guarantee we have something in common with GobTest*
V
ValueGobber
BV
BinaryValueGobber
TV
TextValueGobber
}
type
GobTest5
struct
{
X
int
// guarantee we have something in common with GobTest*
V
*
ValueGobber
X
int
// guarantee we have something in common with GobTest*
V
*
ValueGobber
BV
*
BinaryValueGobber
TV
*
TextValueGobber
}
type
GobTest6
struct
{
X
int
// guarantee we have something in common with GobTest*
V
ValueGobber
W
*
ValueGobber
X
int
// guarantee we have something in common with GobTest*
V
ValueGobber
W
*
ValueGobber
BV
BinaryValueGobber
BW
*
BinaryValueGobber
TV
TextValueGobber
TW
*
TextValueGobber
}
type
GobTest7
struct
{
X
int
// guarantee we have something in common with GobTest*
V
*
ValueGobber
W
ValueGobber
X
int
// guarantee we have something in common with GobTest*
V
*
ValueGobber
W
ValueGobber
BV
*
BinaryValueGobber
BW
BinaryValueGobber
TV
*
TextValueGobber
TW
TextValueGobber
}
type
GobTestIgnoreEncoder
struct
{
...
...
@@ -198,7 +256,9 @@ func TestGobEncoderField(t *testing.T) {
// Now a field that's not a structure.
b
.
Reset
()
gobber
:=
Gobber
(
23
)
err
=
enc
.
Encode
(
GobTest3
{
17
,
&
gobber
})
bgobber
:=
BinaryGobber
(
24
)
tgobber
:=
TextGobber
(
25
)
err
=
enc
.
Encode
(
GobTest3
{
17
,
&
gobber
,
&
bgobber
,
&
tgobber
})
if
err
!=
nil
{
t
.
Fatal
(
"encode error:"
,
err
)
}
...
...
@@ -207,7 +267,7 @@ func TestGobEncoderField(t *testing.T) {
if
err
!=
nil
{
t
.
Fatal
(
"decode error:"
,
err
)
}
if
*
y
.
G
!=
23
{
if
*
y
.
G
!=
23
||
*
y
.
B
!=
24
||
*
y
.
T
!=
25
{
t
.
Errorf
(
"expected '23 got %d"
,
*
y
.
G
)
}
}
...
...
@@ -357,7 +417,7 @@ func TestGobEncoderValueEncoder(t *testing.T) {
// first, string in field to byte in field
b
:=
new
(
bytes
.
Buffer
)
enc
:=
NewEncoder
(
b
)
err
:=
enc
.
Encode
(
GobTest4
{
17
,
ValueGobber
(
"hello"
)})
err
:=
enc
.
Encode
(
GobTest4
{
17
,
ValueGobber
(
"hello"
)
,
BinaryValueGobber
(
"Καλημέρα"
),
TextValueGobber
(
"こんにちは"
)
})
if
err
!=
nil
{
t
.
Fatal
(
"encode error:"
,
err
)
}
...
...
@@ -367,7 +427,7 @@ func TestGobEncoderValueEncoder(t *testing.T) {
if
err
!=
nil
{
t
.
Fatal
(
"decode error:"
,
err
)
}
if
*
x
.
V
!=
"hello"
{
if
*
x
.
V
!=
"hello"
||
*
x
.
BV
!=
"Καλημέρα"
||
*
x
.
TV
!=
"こんにちは"
{
t
.
Errorf
(
"expected `hello` got %s"
,
x
.
V
)
}
}
...
...
@@ -377,13 +437,17 @@ func TestGobEncoderValueEncoder(t *testing.T) {
func
TestGobEncoderValueThenPointer
(
t
*
testing
.
T
)
{
v
:=
ValueGobber
(
"forty-two"
)
w
:=
ValueGobber
(
"six-by-nine"
)
bv
:=
BinaryValueGobber
(
"1nanocentury"
)
bw
:=
BinaryValueGobber
(
"πseconds"
)
tv
:=
TextValueGobber
(
"gravitationalacceleration"
)
tw
:=
TextValueGobber
(
"π²ft/s²"
)
// this was a bug: encoding a GobEncoder by value before a GobEncoder
// pointer would cause duplicate type definitions to be sent.
b
:=
new
(
bytes
.
Buffer
)
enc
:=
NewEncoder
(
b
)
if
err
:=
enc
.
Encode
(
GobTest6
{
42
,
v
,
&
w
});
err
!=
nil
{
if
err
:=
enc
.
Encode
(
GobTest6
{
42
,
v
,
&
w
,
bv
,
&
bw
,
tv
,
&
tw
});
err
!=
nil
{
t
.
Fatal
(
"encode error:"
,
err
)
}
dec
:=
NewDecoder
(
b
)
...
...
@@ -391,6 +455,7 @@ func TestGobEncoderValueThenPointer(t *testing.T) {
if
err
:=
dec
.
Decode
(
x
);
err
!=
nil
{
t
.
Fatal
(
"decode error:"
,
err
)
}
if
got
,
want
:=
x
.
V
,
v
;
got
!=
want
{
t
.
Errorf
(
"v = %q, want %q"
,
got
,
want
)
}
...
...
@@ -399,6 +464,24 @@ func TestGobEncoderValueThenPointer(t *testing.T) {
}
else
if
*
got
!=
want
{
t
.
Errorf
(
"w = %q, want %q"
,
*
got
,
want
)
}
if
got
,
want
:=
x
.
BV
,
bv
;
got
!=
want
{
t
.
Errorf
(
"bv = %q, want %q"
,
got
,
want
)
}
if
got
,
want
:=
x
.
BW
,
bw
;
got
==
nil
{
t
.
Errorf
(
"bw = nil, want %q"
,
want
)
}
else
if
*
got
!=
want
{
t
.
Errorf
(
"bw = %q, want %q"
,
*
got
,
want
)
}
if
got
,
want
:=
x
.
TV
,
tv
;
got
!=
want
{
t
.
Errorf
(
"tv = %q, want %q"
,
got
,
want
)
}
if
got
,
want
:=
x
.
TW
,
tw
;
got
==
nil
{
t
.
Errorf
(
"tw = nil, want %q"
,
want
)
}
else
if
*
got
!=
want
{
t
.
Errorf
(
"tw = %q, want %q"
,
*
got
,
want
)
}
}
// Test that we can use a pointer then a value type of a GobEncoder
...
...
@@ -406,10 +489,14 @@ func TestGobEncoderValueThenPointer(t *testing.T) {
func
TestGobEncoderPointerThenValue
(
t
*
testing
.
T
)
{
v
:=
ValueGobber
(
"forty-two"
)
w
:=
ValueGobber
(
"six-by-nine"
)
bv
:=
BinaryValueGobber
(
"1nanocentury"
)
bw
:=
BinaryValueGobber
(
"πseconds"
)
tv
:=
TextValueGobber
(
"gravitationalacceleration"
)
tw
:=
TextValueGobber
(
"π²ft/s²"
)
b
:=
new
(
bytes
.
Buffer
)
enc
:=
NewEncoder
(
b
)
if
err
:=
enc
.
Encode
(
GobTest7
{
42
,
&
v
,
w
});
err
!=
nil
{
if
err
:=
enc
.
Encode
(
GobTest7
{
42
,
&
v
,
w
,
&
bv
,
bw
,
&
tv
,
tw
});
err
!=
nil
{
t
.
Fatal
(
"encode error:"
,
err
)
}
dec
:=
NewDecoder
(
b
)
...
...
@@ -417,14 +504,33 @@ func TestGobEncoderPointerThenValue(t *testing.T) {
if
err
:=
dec
.
Decode
(
x
);
err
!=
nil
{
t
.
Fatal
(
"decode error:"
,
err
)
}
if
got
,
want
:=
x
.
V
,
v
;
got
==
nil
{
t
.
Errorf
(
"v = nil, want %q"
,
want
)
}
else
if
*
got
!=
want
{
t
.
Errorf
(
"v = %q, want %q"
,
got
,
want
)
t
.
Errorf
(
"v = %q, want %q"
,
*
got
,
want
)
}
if
got
,
want
:=
x
.
W
,
w
;
got
!=
want
{
t
.
Errorf
(
"w = %q, want %q"
,
got
,
want
)
}
if
got
,
want
:=
x
.
BV
,
bv
;
got
==
nil
{
t
.
Errorf
(
"bv = nil, want %q"
,
want
)
}
else
if
*
got
!=
want
{
t
.
Errorf
(
"bv = %q, want %q"
,
*
got
,
want
)
}
if
got
,
want
:=
x
.
BW
,
bw
;
got
!=
want
{
t
.
Errorf
(
"bw = %q, want %q"
,
got
,
want
)
}
if
got
,
want
:=
x
.
TV
,
tv
;
got
==
nil
{
t
.
Errorf
(
"tv = nil, want %q"
,
want
)
}
else
if
*
got
!=
want
{
t
.
Errorf
(
"tv = %q, want %q"
,
*
got
,
want
)
}
if
got
,
want
:=
x
.
TW
,
tw
;
got
!=
want
{
t
.
Errorf
(
"tw = %q, want %q"
,
got
,
want
)
}
}
func
TestGobEncoderFieldTypeError
(
t
*
testing
.
T
)
{
...
...
@@ -521,7 +627,9 @@ func TestGobEncoderIgnoreNonStructField(t *testing.T) {
// First a field that's a structure.
enc
:=
NewEncoder
(
b
)
gobber
:=
Gobber
(
23
)
err
:=
enc
.
Encode
(
GobTest3
{
17
,
&
gobber
})
bgobber
:=
BinaryGobber
(
24
)
tgobber
:=
TextGobber
(
25
)
err
:=
enc
.
Encode
(
GobTest3
{
17
,
&
gobber
,
&
bgobber
,
&
tgobber
})
if
err
!=
nil
{
t
.
Fatal
(
"encode error:"
,
err
)
}
...
...
src/pkg/encoding/gob/type.go
View file @
ce3ba126
...
...
@@ -5,6 +5,7 @@
package
gob
import
(
"encoding"
"errors"
"fmt"
"os"
...
...
@@ -18,14 +19,21 @@ import (
// to the package. It's computed once and stored in a map keyed by reflection
// type.
type
userTypeInfo
struct
{
user
reflect
.
Type
// the type the user handed us
base
reflect
.
Type
// the base type after all indirections
indir
int
// number of indirections to reach the base type
isGobEncoder
bool
// does the type implement GobEncoder?
isGobDecoder
bool
// does the type implement GobDecoder?
encIndir
int8
// number of indirections to reach the receiver type; may be negative
decIndir
int8
// number of indirections to reach the receiver type; may be negative
}
user
reflect
.
Type
// the type the user handed us
base
reflect
.
Type
// the base type after all indirections
indir
int
// number of indirections to reach the base type
externalEnc
int
// xGob, xBinary, or xText
externalDec
int
// xGob, xBinary or xText
encIndir
int8
// number of indirections to reach the receiver type; may be negative
decIndir
int8
// number of indirections to reach the receiver type; may be negative
}
// externalEncoding bits
const
(
xGob
=
1
+
iota
// GobEncoder or GobDecoder
xBinary
// encoding.BinaryMarshaler or encoding.BinaryUnmarshaler
xText
// encoding.TextMarshaler or encoding.TextUnmarshaler
)
var
(
// Protected by an RWMutex because we read it a lot and write
...
...
@@ -75,15 +83,34 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err error) {
}
ut
.
indir
++
}
ut
.
isGobEncoder
,
ut
.
encIndir
=
implementsInterface
(
ut
.
user
,
gobEncoderInterfaceType
)
ut
.
isGobDecoder
,
ut
.
decIndir
=
implementsInterface
(
ut
.
user
,
gobDecoderInterfaceType
)
if
ok
,
indir
:=
implementsInterface
(
ut
.
user
,
gobEncoderInterfaceType
);
ok
{
ut
.
externalEnc
,
ut
.
encIndir
=
xGob
,
indir
}
else
if
ok
,
indir
:=
implementsInterface
(
ut
.
user
,
binaryMarshalerInterfaceType
);
ok
{
ut
.
externalEnc
,
ut
.
encIndir
=
xBinary
,
indir
}
else
if
ok
,
indir
:=
implementsInterface
(
ut
.
user
,
textMarshalerInterfaceType
);
ok
{
ut
.
externalEnc
,
ut
.
encIndir
=
xText
,
indir
}
if
ok
,
indir
:=
implementsInterface
(
ut
.
user
,
gobDecoderInterfaceType
);
ok
{
ut
.
externalDec
,
ut
.
decIndir
=
xGob
,
indir
}
else
if
ok
,
indir
:=
implementsInterface
(
ut
.
user
,
binaryUnmarshalerInterfaceType
);
ok
{
ut
.
externalDec
,
ut
.
decIndir
=
xBinary
,
indir
}
else
if
ok
,
indir
:=
implementsInterface
(
ut
.
user
,
textUnmarshalerInterfaceType
);
ok
{
ut
.
externalDec
,
ut
.
decIndir
=
xText
,
indir
}
userTypeCache
[
rt
]
=
ut
return
}
var
(
gobEncoderInterfaceType
=
reflect
.
TypeOf
((
*
GobEncoder
)(
nil
))
.
Elem
()
gobDecoderInterfaceType
=
reflect
.
TypeOf
((
*
GobDecoder
)(
nil
))
.
Elem
()
gobEncoderInterfaceType
=
reflect
.
TypeOf
((
*
GobEncoder
)(
nil
))
.
Elem
()
gobDecoderInterfaceType
=
reflect
.
TypeOf
((
*
GobDecoder
)(
nil
))
.
Elem
()
binaryMarshalerInterfaceType
=
reflect
.
TypeOf
((
*
encoding
.
BinaryMarshaler
)(
nil
))
.
Elem
()
binaryUnmarshalerInterfaceType
=
reflect
.
TypeOf
((
*
encoding
.
BinaryUnmarshaler
)(
nil
))
.
Elem
()
textMarshalerInterfaceType
=
reflect
.
TypeOf
((
*
encoding
.
TextMarshaler
)(
nil
))
.
Elem
()
textUnmarshalerInterfaceType
=
reflect
.
TypeOf
((
*
encoding
.
TextUnmarshaler
)(
nil
))
.
Elem
()
)
// implementsInterface reports whether the type implements the
...
...
@@ -412,7 +439,7 @@ func newStructType(name string) *structType {
// works through typeIds and userTypeInfos alone.
func
newTypeObject
(
name
string
,
ut
*
userTypeInfo
,
rt
reflect
.
Type
)
(
gobType
,
error
)
{
// Does this type implement GobEncoder?
if
ut
.
isGobEncoder
{
if
ut
.
externalEnc
!=
0
{
return
newGobEncoderType
(
name
),
nil
}
var
err
error
...
...
@@ -593,11 +620,13 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId {
// To maintain binary compatibility, if you extend this type, always put
// the new fields last.
type
wireType
struct
{
ArrayT
*
arrayType
SliceT
*
sliceType
StructT
*
structType
MapT
*
mapType
GobEncoderT
*
gobEncoderType
ArrayT
*
arrayType
SliceT
*
sliceType
StructT
*
structType
MapT
*
mapType
GobEncoderT
*
gobEncoderType
BinaryMarshalerT
*
gobEncoderType
TextMarshalerT
*
gobEncoderType
}
func
(
w
*
wireType
)
string
()
string
{
...
...
@@ -616,6 +645,10 @@ func (w *wireType) string() string {
return
w
.
MapT
.
Name
case
w
.
GobEncoderT
!=
nil
:
return
w
.
GobEncoderT
.
Name
case
w
.
BinaryMarshalerT
!=
nil
:
return
w
.
BinaryMarshalerT
.
Name
case
w
.
TextMarshalerT
!=
nil
:
return
w
.
TextMarshalerT
.
Name
}
return
unknown
}
...
...
@@ -631,7 +664,7 @@ var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock
// typeLock must be held.
func
getTypeInfo
(
ut
*
userTypeInfo
)
(
*
typeInfo
,
error
)
{
rt
:=
ut
.
base
if
ut
.
isGobEncoder
{
if
ut
.
externalEnc
!=
0
{
// We want the user type, not the base type.
rt
=
ut
.
user
}
...
...
@@ -646,12 +679,20 @@ func getTypeInfo(ut *userTypeInfo) (*typeInfo, error) {
}
info
.
id
=
gt
.
id
()
if
ut
.
isGobEncoder
{
if
ut
.
externalEnc
!=
0
{
userType
,
err
:=
getType
(
rt
.
Name
(),
ut
,
rt
)
if
err
!=
nil
{
return
nil
,
err
}
info
.
wire
=
&
wireType
{
GobEncoderT
:
userType
.
id
()
.
gobType
()
.
(
*
gobEncoderType
)}
gt
:=
userType
.
id
()
.
gobType
()
.
(
*
gobEncoderType
)
switch
ut
.
externalEnc
{
case
xGob
:
info
.
wire
=
&
wireType
{
GobEncoderT
:
gt
}
case
xBinary
:
info
.
wire
=
&
wireType
{
BinaryMarshalerT
:
gt
}
case
xText
:
info
.
wire
=
&
wireType
{
TextMarshalerT
:
gt
}
}
typeInfoMap
[
ut
.
user
]
=
info
return
info
,
nil
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment