Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
G
golang
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
golang
Commits
cb0a02f0
Commit
cb0a02f0
authored
Jul 17, 2009
by
Rob Pike
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ignore missing structs
R=rsc DELTA=113 (74 added, 14 deleted, 25 changed) OCL=31776 CL=31776
parent
b751be4c
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
97 additions
and
37 deletions
+97
-37
codec_test.go
src/pkg/gob/codec_test.go
+6
-1
decode.go
src/pkg/gob/decode.go
+74
-19
encoder_test.go
src/pkg/gob/encoder_test.go
+10
-12
type.go
src/pkg/gob/type.go
+7
-5
No files found.
src/pkg/gob/codec_test.go
View file @
cb0a02f0
...
@@ -703,6 +703,7 @@ type IT0 struct {
...
@@ -703,6 +703,7 @@ type IT0 struct {
ignore_f
bool
;
ignore_f
bool
;
ignore_g
string
;
ignore_g
string
;
ignore_h
[]
byte
;
ignore_h
[]
byte
;
ignore_i
*
RT1
;
c
float
;
c
float
;
}
}
...
@@ -718,13 +719,17 @@ func TestIgnoredFields(t *testing.T) {
...
@@ -718,13 +719,17 @@ func TestIgnoredFields(t *testing.T) {
it0
.
ignore_f
=
true
;
it0
.
ignore_f
=
true
;
it0
.
ignore_g
=
"pay no attention"
;
it0
.
ignore_g
=
"pay no attention"
;
it0
.
ignore_h
=
strings
.
Bytes
(
"to the curtain"
);
it0
.
ignore_h
=
strings
.
Bytes
(
"to the curtain"
);
it0
.
ignore_i
=
&
RT1
{
3.1
,
"hi"
,
7
,
"hello"
};
b
:=
new
(
bytes
.
Buffer
);
b
:=
new
(
bytes
.
Buffer
);
encode
(
b
,
it0
);
encode
(
b
,
it0
);
rt0Id
:=
getTypeInfo
(
reflect
.
Typeof
(
it0
))
.
typeId
;
rt0Id
:=
getTypeInfo
(
reflect
.
Typeof
(
it0
))
.
typeId
;
var
rt1
RT1
;
var
rt1
RT1
;
// Wire type is IT0, local type is RT1.
// Wire type is IT0, local type is RT1.
decode
(
b
,
rt0Id
,
&
rt1
);
err
:=
decode
(
b
,
rt0Id
,
&
rt1
);
if
err
!=
nil
{
t
.
Error
(
"error: "
,
err
);
}
if
int
(
it0
.
a
)
!=
rt1
.
a
||
it0
.
b
!=
rt1
.
b
||
it0
.
c
!=
rt1
.
c
{
if
int
(
it0
.
a
)
!=
rt1
.
a
||
it0
.
b
!=
rt1
.
b
||
it0
.
c
!=
rt1
.
c
{
t
.
Errorf
(
"rt1->rt0: expected %v; got %v"
,
it0
,
rt1
);
t
.
Errorf
(
"rt1->rt0: expected %v; got %v"
,
it0
,
rt1
);
}
}
...
...
src/pkg/gob/decode.go
View file @
cb0a02f0
...
@@ -361,6 +361,31 @@ func decodeStruct(engine *decEngine, rtyp *reflect.StructType, b *bytes.Buffer,
...
@@ -361,6 +361,31 @@ func decodeStruct(engine *decEngine, rtyp *reflect.StructType, b *bytes.Buffer,
return
state
.
err
return
state
.
err
}
}
func
ignoreStruct
(
engine
*
decEngine
,
b
*
bytes
.
Buffer
)
os
.
Error
{
state
:=
new
(
decodeState
);
state
.
b
=
b
;
state
.
fieldnum
=
-
1
;
for
state
.
err
==
nil
{
delta
:=
int
(
decodeUint
(
state
));
if
delta
<
0
{
state
.
err
=
os
.
ErrorString
(
"gob ignore decode: corrupted data: negative delta"
);
break
}
if
state
.
err
!=
nil
||
delta
==
0
{
// struct terminator is zero delta fieldnum
break
}
fieldnum
:=
state
.
fieldnum
+
delta
;
if
fieldnum
>=
len
(
engine
.
instr
)
{
state
.
err
=
ErrRange
;
break
;
}
instr
:=
&
engine
.
instr
[
fieldnum
];
instr
.
op
(
instr
,
state
,
unsafe
.
Pointer
(
nil
));
state
.
fieldnum
=
fieldnum
;
}
return
state
.
err
}
func
decodeArrayHelper
(
state
*
decodeState
,
p
uintptr
,
elemOp
decOp
,
elemWid
uintptr
,
length
,
elemIndir
int
)
os
.
Error
{
func
decodeArrayHelper
(
state
*
decodeState
,
p
uintptr
,
elemOp
decOp
,
elemWid
uintptr
,
length
,
elemIndir
int
)
os
.
Error
{
instr
:=
&
decInstr
{
elemOp
,
0
,
elemIndir
,
0
};
instr
:=
&
decInstr
{
elemOp
,
0
,
elemIndir
,
0
};
for
i
:=
0
;
i
<
length
&&
state
.
err
==
nil
;
i
++
{
for
i
:=
0
;
i
<
length
&&
state
.
err
==
nil
;
i
++
{
...
@@ -459,6 +484,7 @@ var decIgnoreOpMap = map[TypeId] decOp {
...
@@ -459,6 +484,7 @@ var decIgnoreOpMap = map[TypeId] decOp {
}
}
func
getDecEnginePtr
(
wireId
TypeId
,
rt
reflect
.
Type
)
(
enginePtr
**
decEngine
,
err
os
.
Error
)
func
getDecEnginePtr
(
wireId
TypeId
,
rt
reflect
.
Type
)
(
enginePtr
**
decEngine
,
err
os
.
Error
)
func
getIgnoreEnginePtr
(
wireId
TypeId
)
(
enginePtr
**
decEngine
,
err
os
.
Error
)
// Return the decoding op for the base type under rt and
// Return the decoding op for the base type under rt and
// the indirection count to reach it.
// the indirection count to reach it.
...
@@ -499,7 +525,7 @@ func decOpFor(wireId TypeId, rt reflect.Type) (decOp, int, os.Error) {
...
@@ -499,7 +525,7 @@ func decOpFor(wireId TypeId, rt reflect.Type) (decOp, int, os.Error) {
return
nil
,
0
,
err
return
nil
,
0
,
err
}
}
op
=
func
(
i
*
decInstr
,
state
*
decodeState
,
p
unsafe
.
Pointer
)
{
op
=
func
(
i
*
decInstr
,
state
*
decodeState
,
p
unsafe
.
Pointer
)
{
// indirect through
info
to delay evaluation for recursive structs
// indirect through
enginePtr
to delay evaluation for recursive structs
state
.
err
=
decodeStruct
(
*
enginePtr
,
t
,
state
.
b
,
uintptr
(
p
),
i
.
indir
)
state
.
err
=
decodeStruct
(
*
enginePtr
,
t
,
state
.
b
,
uintptr
(
p
),
i
.
indir
)
};
};
}
}
...
@@ -537,7 +563,15 @@ func decIgnoreOpFor(wireId TypeId) (decOp, os.Error) {
...
@@ -537,7 +563,15 @@ func decIgnoreOpFor(wireId TypeId) (decOp, os.Error) {
};
};
case
*
structType
:
case
*
structType
:
// TODO: write an ignore engine for structs
// Generate a closure that calls out to the engine for the nested type.
enginePtr
,
err
:=
getIgnoreEnginePtr
(
wireId
);
if
err
!=
nil
{
return
nil
,
err
}
op
=
func
(
i
*
decInstr
,
state
*
decodeState
,
p
unsafe
.
Pointer
)
{
// indirect through enginePtr to delay evaluation for recursive structs
state
.
err
=
ignoreStruct
(
*
enginePtr
,
state
.
b
)
};
}
}
}
}
if
op
==
nil
{
if
op
==
nil
{
...
@@ -547,7 +581,8 @@ func decIgnoreOpFor(wireId TypeId) (decOp, os.Error) {
...
@@ -547,7 +581,8 @@ func decIgnoreOpFor(wireId TypeId) (decOp, os.Error) {
}
}
// Are these two gob Types compatible?
// Are these two gob Types compatible?
// Answers the question for basic types, arrays, and slices. Defers for structs.
// Answers the question for basic types, arrays, and slices.
// Structs are considered ok; fields will be checked later.
func
compatibleType
(
fr
reflect
.
Type
,
fw
TypeId
)
bool
{
func
compatibleType
(
fr
reflect
.
Type
,
fw
TypeId
)
bool
{
for
{
for
{
if
pt
,
ok
:=
fr
.
(
*
reflect
.
PtrType
);
ok
{
if
pt
,
ok
:=
fr
.
(
*
reflect
.
PtrType
);
ok
{
...
@@ -592,8 +627,6 @@ func compatibleType(fr reflect.Type, fw TypeId) bool {
...
@@ -592,8 +627,6 @@ func compatibleType(fr reflect.Type, fw TypeId) bool {
return
fw
==
tFloat
;
return
fw
==
tFloat
;
case
*
reflect
.
StringType
:
case
*
reflect
.
StringType
:
return
fw
==
tString
;
return
fw
==
tString
;
case
*
reflect
.
StructType
:
return
true
;
// defer for now
case
*
reflect
.
ArrayType
:
case
*
reflect
.
ArrayType
:
aw
,
ok
:=
fw
.
gobType
()
.
(
*
arrayType
);
aw
,
ok
:=
fw
.
gobType
()
.
(
*
arrayType
);
return
ok
&&
t
.
Len
()
==
aw
.
Len
&&
compatibleType
(
t
.
Elem
(),
aw
.
Elem
);
return
ok
&&
t
.
Len
()
==
aw
.
Len
&&
compatibleType
(
t
.
Elem
(),
aw
.
Elem
);
...
@@ -604,7 +637,10 @@ func compatibleType(fr reflect.Type, fw TypeId) bool {
...
@@ -604,7 +637,10 @@ func compatibleType(fr reflect.Type, fw TypeId) bool {
return
fw
==
tBytes
return
fw
==
tBytes
}
}
sw
,
ok
:=
fw
.
gobType
()
.
(
*
sliceType
);
sw
,
ok
:=
fw
.
gobType
()
.
(
*
sliceType
);
return
ok
&&
compatibleType
(
t
.
Elem
(),
sw
.
Elem
);
elem
,
_
:=
indirect
(
t
.
Elem
());
return
ok
&&
compatibleType
(
elem
,
sw
.
Elem
);
case
*
reflect
.
StructType
:
return
true
;
}
}
return
true
;
return
true
;
}
}
...
@@ -624,7 +660,6 @@ func compileDec(wireId TypeId, rt reflect.Type) (engine *decEngine, err os.Error
...
@@ -624,7 +660,6 @@ func compileDec(wireId TypeId, rt reflect.Type) (engine *decEngine, err os.Error
localField
,
present
:=
srt
.
FieldByName
(
wireField
.
name
);
localField
,
present
:=
srt
.
FieldByName
(
wireField
.
name
);
// TODO(r): anonymous names
// TODO(r): anonymous names
if
!
present
||
localField
.
Anonymous
{
if
!
present
||
localField
.
Anonymous
{
println
(
"no matching field"
,
wireField
.
name
,
"in type"
,
wireId
.
String
());
op
,
err
:=
decIgnoreOpFor
(
wireField
.
typeId
);
op
,
err
:=
decIgnoreOpFor
(
wireField
.
typeId
);
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
...
@@ -633,7 +668,7 @@ func compileDec(wireId TypeId, rt reflect.Type) (engine *decEngine, err os.Error
...
@@ -633,7 +668,7 @@ func compileDec(wireId TypeId, rt reflect.Type) (engine *decEngine, err os.Error
continue
;
continue
;
}
}
if
!
compatibleType
(
localField
.
Type
,
wireField
.
typeId
)
{
if
!
compatibleType
(
localField
.
Type
,
wireField
.
typeId
)
{
return
nil
,
os
.
ErrorString
(
"gob:
TODO: wrong type for field "
+
wireField
.
name
+
" in type "
+
wireId
.
String
());
return
nil
,
os
.
ErrorString
(
"gob:
wrong type for field "
+
wireField
.
name
+
" in type "
+
wireId
.
Name
());
}
}
op
,
indir
,
err
:=
decOpFor
(
wireField
.
typeId
,
localField
.
Type
);
op
,
indir
,
err
:=
decOpFor
(
wireField
.
typeId
,
localField
.
Type
);
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -645,22 +680,42 @@ func compileDec(wireId TypeId, rt reflect.Type) (engine *decEngine, err os.Error
...
@@ -645,22 +680,42 @@ func compileDec(wireId TypeId, rt reflect.Type) (engine *decEngine, err os.Error
return
;
return
;
}
}
var
decoderCache
=
make
(
map
[
reflect
.
Type
]
map
[
TypeId
]
**
decEngine
)
var
ignorerCache
=
make
(
map
[
TypeId
]
**
decEngine
)
// typeLock must be held.
// typeLock must be held.
func
getDecEnginePtr
(
wireId
TypeId
,
rt
reflect
.
Type
)
(
enginePtr
**
decEngine
,
err
os
.
Error
)
{
func
getDecEnginePtr
(
wireId
TypeId
,
rt
reflect
.
Type
)
(
enginePtr
**
decEngine
,
err
os
.
Error
)
{
info
:=
getTypeInfo
(
rt
);
// TODO: eliminate this; creates a gobType you don't need.
decoderMap
,
ok
:=
decoderCache
[
rt
];
var
ok
bool
;
if
!
ok
{
if
enginePtr
,
ok
=
info
.
decoderPtr
[
wireId
];
!
ok
{
decoderMap
=
make
(
map
[
TypeId
]
**
decEngine
);
if
info
.
typeId
.
gobType
()
==
nil
{
decoderCache
[
rt
]
=
decoderMap
;
_pkg
,
name
:=
rt
.
Name
();
info
.
typeId
=
newType
(
name
,
rt
)
.
id
();
}
}
// mark this engine as underway before compiling to handle recursive types.
if
enginePtr
,
ok
=
decoderMap
[
wireId
];
!
ok
{
// To handle recursive types, mark this engine as underway before compiling.
enginePtr
=
new
(
*
decEngine
);
enginePtr
=
new
(
*
decEngine
);
info
.
decoderPtr
[
wireId
]
=
enginePtr
;
decoderMap
[
wireId
]
=
enginePtr
;
*
enginePtr
,
err
=
compileDec
(
wireId
,
rt
);
*
enginePtr
,
err
=
compileDec
(
wireId
,
rt
);
if
err
!=
nil
{
if
err
!=
nil
{
info
.
decoderPtr
[
wireId
]
=
nil
,
false
;
decoderMap
[
wireId
]
=
nil
,
false
;
}
}
return
}
// When ignoring data, in effect we compile it into this type
type
emptyStruct
struct
{}
var
emptyStructType
=
reflect
.
Typeof
(
emptyStruct
{})
// typeLock must be held.
func
getIgnoreEnginePtr
(
wireId
TypeId
)
(
enginePtr
**
decEngine
,
err
os
.
Error
)
{
var
ok
bool
;
if
enginePtr
,
ok
=
ignorerCache
[
wireId
];
!
ok
{
// To handle recursive types, mark this engine as underway before compiling.
enginePtr
=
new
(
*
decEngine
);
ignorerCache
[
wireId
]
=
enginePtr
;
*
enginePtr
,
err
=
compileDec
(
wireId
,
emptyStructType
);
if
err
!=
nil
{
ignorerCache
[
wireId
]
=
nil
,
false
;
}
}
}
}
return
return
...
@@ -685,9 +740,9 @@ func decode(b *bytes.Buffer, wireId TypeId, e interface{}) os.Error {
...
@@ -685,9 +740,9 @@ func decode(b *bytes.Buffer, wireId TypeId, e interface{}) os.Error {
return
err
return
err
}
}
engine
:=
*
enginePtr
;
engine
:=
*
enginePtr
;
if
engine
.
numInstr
==
0
&&
st
.
NumField
()
>
0
{
if
engine
.
numInstr
==
0
&&
st
.
NumField
()
>
0
&&
len
(
wireId
.
gobType
()
.
(
*
structType
)
.
field
)
>
0
{
path
,
name
:=
rt
.
Name
();
path
,
name
:=
rt
.
Name
();
return
os
.
ErrorString
(
"type mismatch: no fields matched compiling decoder for "
+
name
)
return
os
.
ErrorString
(
"
gob:
type mismatch: no fields matched compiling decoder for "
+
name
)
}
}
return
decodeStruct
(
engine
,
rt
.
(
*
reflect
.
StructType
),
b
,
uintptr
(
v
.
Addr
()),
0
);
return
decodeStruct
(
engine
,
rt
.
(
*
reflect
.
StructType
),
b
,
uintptr
(
v
.
Addr
()),
0
);
}
}
src/pkg/gob/encoder_test.go
View file @
cb0a02f0
...
@@ -35,12 +35,7 @@ type ET3 struct {
...
@@ -35,12 +35,7 @@ type ET3 struct {
type
ET4
struct
{
type
ET4
struct
{
a
int
;
a
int
;
et2
*
ET1
;
et2
*
ET1
;
next
*
ET2
;
next
int
;
}
// Has different type for a self-referencing field compared to ET1
type
ET5
struct
{
next
*
ET2
;
}
}
func
TestBasicEncoder
(
t
*
testing
.
T
)
{
func
TestBasicEncoder
(
t
*
testing
.
T
)
{
...
@@ -206,7 +201,8 @@ func TestEncoderDecoder(t *testing.T) {
...
@@ -206,7 +201,8 @@ func TestEncoderDecoder(t *testing.T) {
}
}
// Run one value through the encoder/decoder, but use the wrong type.
// Run one value through the encoder/decoder, but use the wrong type.
func
badTypeCheck
(
e
interface
{},
msg
string
,
t
*
testing
.
T
)
{
// Input is always an ET1; we compare it to whatever is under 'e'.
func
badTypeCheck
(
e
interface
{},
shouldFail
bool
,
msg
string
,
t
*
testing
.
T
)
{
b
:=
new
(
bytes
.
Buffer
);
b
:=
new
(
bytes
.
Buffer
);
enc
:=
NewEncoder
(
b
);
enc
:=
NewEncoder
(
b
);
et1
:=
new
(
ET1
);
et1
:=
new
(
ET1
);
...
@@ -218,15 +214,17 @@ func badTypeCheck(e interface{}, msg string, t *testing.T) {
...
@@ -218,15 +214,17 @@ func badTypeCheck(e interface{}, msg string, t *testing.T) {
}
}
dec
:=
NewDecoder
(
b
);
dec
:=
NewDecoder
(
b
);
dec
.
Decode
(
e
);
dec
.
Decode
(
e
);
if
dec
.
state
.
err
==
nil
{
if
shouldFail
&&
(
dec
.
state
.
err
==
nil
)
{
t
.
Error
(
"expected error for"
,
msg
);
t
.
Error
(
"expected error for"
,
msg
);
}
}
if
!
shouldFail
&&
(
dec
.
state
.
err
!=
nil
)
{
t
.
Error
(
"unexpected error for"
,
msg
);
}
}
}
// Test that we recognize a bad type the first time.
// Test that we recognize a bad type the first time.
func
TestWrongTypeDecoder
(
t
*
testing
.
T
)
{
func
TestWrongTypeDecoder
(
t
*
testing
.
T
)
{
badTypeCheck
(
new
(
ET2
),
"no fields in common"
,
t
);
badTypeCheck
(
new
(
ET2
),
true
,
"no fields in common"
,
t
);
badTypeCheck
(
new
(
ET3
),
"different name of field"
,
t
);
badTypeCheck
(
new
(
ET3
),
false
,
"different name of field"
,
t
);
badTypeCheck
(
new
(
ET4
),
"different type of field"
,
t
);
badTypeCheck
(
new
(
ET4
),
true
,
"different type of field"
,
t
);
badTypeCheck
(
new
(
ET5
),
"different type of self-reference field"
,
t
);
}
}
src/pkg/gob/type.go
View file @
cb0a02f0
...
@@ -23,6 +23,7 @@ var typeLock sync.Mutex // set while building a type
...
@@ -23,6 +23,7 @@ var typeLock sync.Mutex // set while building a type
type
gobType
interface
{
type
gobType
interface
{
id
()
TypeId
;
id
()
TypeId
;
setId
(
id
TypeId
);
setId
(
id
TypeId
);
Name
()
string
;
String
()
string
;
String
()
string
;
safeString
(
seen
map
[
TypeId
]
bool
)
string
;
safeString
(
seen
map
[
TypeId
]
bool
)
string
;
}
}
...
@@ -47,6 +48,10 @@ func (t TypeId) String() string {
...
@@ -47,6 +48,10 @@ func (t TypeId) String() string {
return
t
.
gobType
()
.
String
()
return
t
.
gobType
()
.
String
()
}
}
func
(
t
TypeId
)
Name
()
string
{
return
t
.
gobType
()
.
Name
()
}
// Common elements of all types.
// Common elements of all types.
type
commonType
struct
{
type
commonType
struct
{
name
string
;
name
string
;
...
@@ -236,7 +241,8 @@ func newTypeObject(name string, rt reflect.Type) gobType {
...
@@ -236,7 +241,8 @@ func newTypeObject(name string, rt reflect.Type) gobType {
if
_
,
ok
:=
t
.
Elem
()
.
(
*
reflect
.
Uint8Type
);
ok
{
if
_
,
ok
:=
t
.
Elem
()
.
(
*
reflect
.
Uint8Type
);
ok
{
return
tBytes
.
gobType
()
return
tBytes
.
gobType
()
}
}
return
newSliceType
(
name
,
newType
(
""
,
t
.
Elem
()));
_
,
elemName
:=
t
.
Elem
()
.
Name
();
return
newSliceType
(
name
,
newType
(
elemName
,
t
.
Elem
()));
case
*
reflect
.
StructType
:
case
*
reflect
.
StructType
:
// Install the struct type itself before the fields so recursive
// Install the struct type itself before the fields so recursive
...
@@ -325,9 +331,6 @@ type decEngine struct // defined in decode.go
...
@@ -325,9 +331,6 @@ type decEngine struct // defined in decode.go
type
encEngine
struct
// defined in encode.go
type
encEngine
struct
// defined in encode.go
type
typeInfo
struct
{
type
typeInfo
struct
{
typeId
TypeId
;
typeId
TypeId
;
// Decoder engine to convert TypeId.Type() to this type. Stored as a pointer to a
// pointer to aid construction of recursive types. Protected by typeLock.
decoderPtr
map
[
TypeId
]
**
decEngine
;
encoder
*
encEngine
;
encoder
*
encEngine
;
wire
*
wireType
;
wire
*
wireType
;
}
}
...
@@ -345,7 +348,6 @@ func getTypeInfo(rt reflect.Type) *typeInfo {
...
@@ -345,7 +348,6 @@ func getTypeInfo(rt reflect.Type) *typeInfo {
info
=
new
(
typeInfo
);
info
=
new
(
typeInfo
);
path
,
name
:=
rt
.
Name
();
path
,
name
:=
rt
.
Name
();
info
.
typeId
=
getType
(
name
,
rt
)
.
id
();
info
.
typeId
=
getType
(
name
,
rt
)
.
id
();
info
.
decoderPtr
=
make
(
map
[
TypeId
]
**
decEngine
);
// assume it's a struct type
// assume it's a struct type
info
.
wire
=
&
wireType
{
info
.
typeId
.
gobType
()
.
(
*
structType
)};
info
.
wire
=
&
wireType
{
info
.
typeId
.
gobType
()
.
(
*
structType
)};
typeInfoMap
[
rt
]
=
info
;
typeInfoMap
[
rt
]
=
info
;
...
...
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