| | |
| | |
| | |
| |
|
| | package gob |
| |
|
| | import ( |
| | "errors" |
| | "io" |
| | "reflect" |
| | "sync" |
| | ) |
| |
|
| | |
| | |
| | |
| | type Encoder struct { |
| | mutex sync.Mutex |
| | w []io.Writer |
| | sent map[reflect.Type]typeId |
| | countState *encoderState |
| | freeList *encoderState |
| | byteBuf encBuffer |
| | err error |
| | } |
| |
|
| | |
| | |
| | |
| | const maxLength = 9 |
| | var spaceForLength = make([]byte, maxLength) |
| |
|
| | |
| | func NewEncoder(w io.Writer) *Encoder { |
| | enc := new(Encoder) |
| | enc.w = []io.Writer{w} |
| | enc.sent = make(map[reflect.Type]typeId) |
| | enc.countState = enc.newEncoderState(new(encBuffer)) |
| | return enc |
| | } |
| |
|
| | |
| | func (enc *Encoder) writer() io.Writer { |
| | return enc.w[len(enc.w)-1] |
| | } |
| |
|
| | |
| | func (enc *Encoder) pushWriter(w io.Writer) { |
| | enc.w = append(enc.w, w) |
| | } |
| |
|
| | |
| | func (enc *Encoder) popWriter() { |
| | enc.w = enc.w[0 : len(enc.w)-1] |
| | } |
| |
|
| | func (enc *Encoder) setError(err error) { |
| | if enc.err == nil { |
| | enc.err = err |
| | } |
| | } |
| |
|
| | |
| | func (enc *Encoder) writeMessage(w io.Writer, b *encBuffer) { |
| | |
| | |
| | |
| | message := b.Bytes() |
| | messageLen := len(message) - maxLength |
| | |
| | if messageLen >= tooBig { |
| | enc.setError(errors.New("gob: encoder: message too big")) |
| | return |
| | } |
| | |
| | enc.countState.b.Reset() |
| | enc.countState.encodeUint(uint64(messageLen)) |
| | |
| | offset := maxLength - enc.countState.b.Len() |
| | copy(message[offset:], enc.countState.b.Bytes()) |
| | |
| | _, err := w.Write(message[offset:]) |
| | |
| | b.Reset() |
| | b.Write(spaceForLength) |
| | if err != nil { |
| | enc.setError(err) |
| | } |
| | } |
| |
|
| | |
| | |
| | func (enc *Encoder) sendActualType(w io.Writer, state *encoderState, ut *userTypeInfo, actual reflect.Type) (sent bool) { |
| | if _, alreadySent := enc.sent[actual]; alreadySent { |
| | return false |
| | } |
| | info, err := getTypeInfo(ut) |
| | if err != nil { |
| | enc.setError(err) |
| | return |
| | } |
| | |
| | |
| | state.encodeInt(-int64(info.id)) |
| | |
| | enc.encode(state.b, reflect.ValueOf(info.wire), wireTypeUserInfo) |
| | enc.writeMessage(w, state.b) |
| | if enc.err != nil { |
| | return |
| | } |
| |
|
| | |
| | enc.sent[ut.base] = info.id |
| | if ut.user != ut.base { |
| | enc.sent[ut.user] = info.id |
| | } |
| | |
| | switch st := actual; st.Kind() { |
| | case reflect.Struct: |
| | for i := 0; i < st.NumField(); i++ { |
| | if isExported(st.Field(i).Name) { |
| | enc.sendType(w, state, st.Field(i).Type) |
| | } |
| | } |
| | case reflect.Array, reflect.Slice: |
| | enc.sendType(w, state, st.Elem()) |
| | case reflect.Map: |
| | enc.sendType(w, state, st.Key()) |
| | enc.sendType(w, state, st.Elem()) |
| | } |
| | return true |
| | } |
| |
|
| | |
| | func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Type) (sent bool) { |
| | ut := userType(origt) |
| | if ut.externalEnc != 0 { |
| | |
| | |
| | return enc.sendActualType(w, state, ut, ut.base) |
| | } |
| |
|
| | |
| | switch rt := ut.base; rt.Kind() { |
| | default: |
| | |
| | return |
| | case reflect.Slice: |
| | |
| | if rt.Elem().Kind() == reflect.Uint8 { |
| | return |
| | } |
| | |
| | break |
| | case reflect.Array: |
| | |
| | break |
| | case reflect.Map: |
| | |
| | break |
| | case reflect.Struct: |
| | |
| | break |
| | case reflect.Chan, reflect.Func: |
| | |
| | return |
| | } |
| |
|
| | return enc.sendActualType(w, state, ut, ut.base) |
| | } |
| |
|
| | |
| | |
| | |
| | func (enc *Encoder) Encode(e any) error { |
| | return enc.EncodeValue(reflect.ValueOf(e)) |
| | } |
| |
|
| | |
| | |
| | |
| | func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *userTypeInfo) { |
| | |
| | |
| | rt := ut.base |
| | if ut.externalEnc != 0 { |
| | rt = ut.user |
| | } |
| | if _, alreadySent := enc.sent[rt]; !alreadySent { |
| | |
| | sent := enc.sendType(w, state, rt) |
| | if enc.err != nil { |
| | return |
| | } |
| | |
| | |
| | |
| | if !sent { |
| | info, err := getTypeInfo(ut) |
| | if err != nil { |
| | enc.setError(err) |
| | return |
| | } |
| | enc.sent[rt] = info.id |
| | } |
| | } |
| | } |
| |
|
| | |
| | func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) { |
| | |
| | state.encodeInt(int64(enc.sent[ut.base])) |
| | } |
| |
|
| | |
| | |
| | |
| | func (enc *Encoder) EncodeValue(value reflect.Value) error { |
| | if value.Kind() == reflect.Invalid { |
| | return errors.New("gob: cannot encode nil value") |
| | } |
| | if value.Kind() == reflect.Pointer && value.IsNil() { |
| | panic("gob: cannot encode nil pointer of type " + value.Type().String()) |
| | } |
| |
|
| | |
| | |
| | enc.mutex.Lock() |
| | defer enc.mutex.Unlock() |
| |
|
| | |
| | enc.w = enc.w[0:1] |
| |
|
| | ut, err := validUserType(value.Type()) |
| | if err != nil { |
| | return err |
| | } |
| |
|
| | enc.err = nil |
| | enc.byteBuf.Reset() |
| | enc.byteBuf.Write(spaceForLength) |
| | state := enc.newEncoderState(&enc.byteBuf) |
| |
|
| | enc.sendTypeDescriptor(enc.writer(), state, ut) |
| | enc.sendTypeId(state, ut) |
| | if enc.err != nil { |
| | return enc.err |
| | } |
| |
|
| | |
| | enc.encode(state.b, value, ut) |
| | if enc.err == nil { |
| | enc.writeMessage(enc.writer(), state.b) |
| | } |
| |
|
| | enc.freeEncoderState(state) |
| | return enc.err |
| | } |
| |
|