Skip to content

Commit 4e4119b

Browse files
author
Charles-Antoine Mathieu
committed
Allow to RegisterName at the Decoder level
1 parent a3b05c2 commit 4e4119b

File tree

3 files changed

+43
-12
lines changed

3 files changed

+43
-12
lines changed

decode.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -659,10 +659,18 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu
659659
if len(name) > 1024 {
660660
errorf("name too long (%d bytes): %.20q...", len(name), name)
661661
}
662+
662663
// The concrete type must be registered.
663-
typi, ok := nameToConcreteType.Load(string(name))
664+
var typi interface{}
665+
var ok bool
666+
if dec.nameToConcreteType != nil {
667+
typi, ok = dec.nameToConcreteType.Load(string(name))
668+
}
664669
if !ok {
665-
errorf("name not registered for interface: %q", name)
670+
typi, ok = nameToConcreteType.Load(string(name))
671+
if !ok {
672+
errorf("name not registered for interface: %q", name)
673+
}
666674
}
667675
typ := typi.(reflect.Type)
668676

decoder.go

+32-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package gob
77
import (
88
"bufio"
99
"errors"
10+
"fmt"
1011
"io"
1112
"reflect"
1213
"sync"
@@ -25,15 +26,16 @@ const tooBig = (1 << 30) << (^uint(0) >> 62)
2526
// and its limits are not configurable. Take caution when decoding gob data
2627
// from untrusted sources.
2728
type Decoder struct {
28-
mutex sync.Mutex // each item must be received atomically
29-
r io.Reader // source of the data
30-
buf decBuffer // buffer for more efficient i/o from r
31-
wireType map[typeId]*wireType // map from remote ID to local description
32-
decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
33-
ignorerCache map[typeId]**decEngine // ditto for ignored objects
34-
freeList *decoderState // list of free decoderStates; avoids reallocation
35-
countBuf []byte // used for decoding integers while parsing messages
36-
err error
29+
mutex sync.Mutex // each item must be received atomically
30+
r io.Reader // source of the data
31+
buf decBuffer // buffer for more efficient i/o from r
32+
wireType map[typeId]*wireType // map from remote ID to local description
33+
decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
34+
ignorerCache map[typeId]**decEngine // ditto for ignored objects
35+
freeList *decoderState // list of free decoderStates; avoids reallocation
36+
countBuf []byte // used for decoding integers while parsing messages
37+
err error
38+
nameToConcreteType *sync.Map // map[string]reflect.Type
3739
}
3840

3941
// NewDecoder returns a new decoder that reads from the io.Reader.
@@ -54,6 +56,27 @@ func NewDecoder(r io.Reader) *Decoder {
5456
return dec
5557
}
5658

59+
func (dec *Decoder) RegisterName(name string, value interface{}) {
60+
if name == "" {
61+
// reserved for nil
62+
panic("attempt to register empty name")
63+
}
64+
65+
if dec.nameToConcreteType == nil {
66+
dec.nameToConcreteType = &sync.Map{}
67+
}
68+
69+
ut := userType(reflect.TypeOf(value))
70+
71+
// Check for incompatible duplicates. The name must refer to the
72+
// same user type, and vice versa.
73+
74+
// Store the name and type provided by the user....
75+
if t, dup := dec.nameToConcreteType.LoadOrStore(name, reflect.TypeOf(value)); dup && t != ut.user {
76+
panic(fmt.Sprintf("gob: registering duplicate types for %q: %s != %s", name, t, ut.user))
77+
}
78+
}
79+
5780
// recvType loads the definition of a type.
5881
func (dec *Decoder) recvType(id typeId) {
5982
// Have we already seen this type? That's an error

type_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ func TestRegistrationNaming(t *testing.T) {
172172
name string
173173
}{
174174
{&N1{}, "*gob.N1"},
175-
{N2{}, "encoding/gob.N2"},
175+
{N2{}, "github.com/root-gg/gob.N2"},
176176
}
177177

178178
for _, tc := range testCases {

0 commit comments

Comments
 (0)