Skip to content

Commit 48b44e8

Browse files
authored
refactor(go): refactor go error processing (#3069)
## Why? The Go serializer interface methods previously returned `error` values, requiring error checking at every call site. This pattern was inconsistent with the C++ implementation and led to verbose, repetitive error handling code throughout the codebase. ## What does this PR do? Refactors Go error handling to use a **centralized delayed error pattern**, similar to the C++ implementation: ### Interface Changes - **Serializer interface** methods no longer return `error`: - `Write(ctx *WriteContext, refMode RefMode, writeType bool, value reflect.Value)` - `WriteData(ctx *WriteContext, value reflect.Value)` - `Read(ctx *ReadContext, refMode RefMode, readType bool, value reflect.Value)` - `ReadData(ctx *ReadContext, type_ reflect.Type, value reflect.Value)` - `ReadWithTypeInfo(ctx *ReadContext, refMode RefMode, typeInfo *TypeInfo, value reflect.Value)` ### Error Handling Pattern - Errors are set via `ctx.SetError(FromError(err))` or `ctx.SetError(DeserializationErrorf(...))` - Early return on error using `if ctx.HasError() { return }` - Final error check at API boundaries via `ctx.CheckError()` or `ctx.TakeError()` ### Files Modified - **Serializer implementations**: array_primitive.go, map_primitive.go, struct.go, skip.go - **Context files**: reader.go, writer.go - **Cleanup**: enum.go, slice_primitive.go (removed unused fmt imports) - **Code generator**: codegen/generator.go, codegen/encoder.go, codegen/decoder.go - **Generated test file**: tests/structs_fory_gen.go ### Benefits - Cleaner, more consistent code with less boilerplate - Aligns with C++ implementation pattern - Errors are accumulated in context and checked at API boundaries - Reduces cognitive overhead when writing serializers ## Related issues #2982 #3012 Closes #3026 ## Does this PR introduce any user-facing change? - [x] Does this PR introduce any public API change? - Yes, the `Serializer` interface method signatures have changed (no longer return `error`) - This is an internal API change; the public `Fory.Serialize()` and `Fory.Deserialize()` APIs remain unchanged - [ ] Does this PR introduce any binary protocol compatibility change? - No, the wire format is unchanged ## Benchmark No performance regression expected - this is a refactoring of error handling flow, not serialization logic.
1 parent 4d16792 commit 48b44e8

34 files changed

Lines changed: 3303 additions & 2393 deletions

go/fory/array.go

Lines changed: 111 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -24,48 +24,53 @@ import (
2424
// writeArrayRefAndType handles reference and type writing for array serializers.
2525
// Arrays are value types, so ref handling is simpler than slices.
2626
// Returns true if the value was already written, false if data should be written.
27-
func writeArrayRefAndType(ctx *WriteContext, refMode RefMode, writeType bool, value reflect.Value, typeId TypeId) (bool, error) {
27+
func writeArrayRefAndType(ctx *WriteContext, refMode RefMode, writeType bool, value reflect.Value, typeId TypeId) bool {
2828
if refMode != RefModeNone {
2929
// Arrays are value types, just write NotNullValueFlag
3030
ctx.Buffer().WriteInt8(NotNullValueFlag)
3131
}
3232
if writeType {
3333
ctx.Buffer().WriteVaruint32Small7(uint32(typeId))
3434
}
35-
return false, nil
35+
return false
3636
}
3737

3838
// readArrayRefAndType handles reference and type reading for array serializers.
3939
// Returns true if a reference was resolved (value already set), false if data should be read.
40-
func readArrayRefAndType(ctx *ReadContext, refMode RefMode, readType bool, value reflect.Value) (bool, error) {
40+
func readArrayRefAndType(ctx *ReadContext, refMode RefMode, readType bool, value reflect.Value) bool {
4141
buf := ctx.Buffer()
42+
err := ctx.Err()
4243
if refMode != RefModeNone {
43-
refID, err := ctx.RefResolver().TryPreserveRefId(buf)
44-
if err != nil {
45-
return false, err
44+
refID, refErr := ctx.RefResolver().TryPreserveRefId(buf)
45+
if refErr != nil {
46+
ctx.SetError(FromError(refErr))
47+
return false
4648
}
4749
if int8(refID) < NotNullValueFlag {
4850
obj := ctx.RefResolver().GetReadObject(refID)
4951
if obj.IsValid() {
5052
value.Set(obj)
5153
}
52-
return true, nil
54+
return true
5355
}
5456
}
5557
if readType {
56-
typeID := buf.ReadVaruint32Small7()
58+
typeID := buf.ReadVaruint32Small7(err)
59+
if ctx.HasError() {
60+
return false
61+
}
5762
if IsNamespacedType(TypeId(typeID)) {
5863
_, _ = ctx.TypeResolver().readTypeInfoWithTypeID(buf, typeID)
5964
}
6065
}
61-
return false, nil
66+
return false
6267
}
6368

6469
// Array serializers
6570

6671
type arraySerializer struct{}
6772

68-
func (s arraySerializer) WriteData(ctx *WriteContext, value reflect.Value) error {
73+
func (s arraySerializer) WriteData(ctx *WriteContext, value reflect.Value) {
6974
buf := ctx.Buffer()
7075
length := value.Len()
7176
buf.WriteVaruint32(uint32(length))
@@ -74,36 +79,35 @@ func (s arraySerializer) WriteData(ctx *WriteContext, value reflect.Value) error
7479
buf.WriteInt8(NotNullValueFlag)
7580
_ = elem
7681
}
77-
return nil
7882
}
7983

80-
func (s arraySerializer) Write(ctx *WriteContext, refMode RefMode, writeType bool, value reflect.Value) error {
81-
_, err := writeArrayRefAndType(ctx, refMode, writeType, value, -LIST)
82-
if err != nil {
83-
return err
84+
func (s arraySerializer) Write(ctx *WriteContext, refMode RefMode, writeType bool, value reflect.Value) {
85+
writeArrayRefAndType(ctx, refMode, writeType, value, -LIST)
86+
if ctx.HasError() {
87+
return
8488
}
85-
return s.WriteData(ctx, value)
89+
s.WriteData(ctx, value)
8690
}
8791

88-
func (s arraySerializer) ReadData(ctx *ReadContext, type_ reflect.Type, value reflect.Value) error {
92+
func (s arraySerializer) ReadData(ctx *ReadContext, type_ reflect.Type, value reflect.Value) {
8993
buf := ctx.Buffer()
90-
length := int(buf.ReadVaruint32())
94+
err := ctx.Err()
95+
length := int(buf.ReadVaruint32(err))
9196
for i := 0; i < length; i++ {
92-
_ = buf.ReadInt8()
97+
_ = buf.ReadInt8(err)
9398
}
94-
return nil
9599
}
96100

97-
func (s arraySerializer) Read(ctx *ReadContext, refMode RefMode, readType bool, value reflect.Value) error {
98-
done, err := readArrayRefAndType(ctx, refMode, readType, value)
99-
if done || err != nil {
100-
return err
101+
func (s arraySerializer) Read(ctx *ReadContext, refMode RefMode, readType bool, value reflect.Value) {
102+
done := readArrayRefAndType(ctx, refMode, readType, value)
103+
if done || ctx.HasError() {
104+
return
101105
}
102-
return s.ReadData(ctx, value.Type(), value)
106+
s.ReadData(ctx, value.Type(), value)
103107
}
104108

105-
func (s arraySerializer) ReadWithTypeInfo(ctx *ReadContext, refMode RefMode, typeInfo *TypeInfo, value reflect.Value) error {
106-
return s.Read(ctx, refMode, false, value)
109+
func (s arraySerializer) ReadWithTypeInfo(ctx *ReadContext, refMode RefMode, typeInfo *TypeInfo, value reflect.Value) {
110+
s.Read(ctx, refMode, false, value)
107111
}
108112

109113
// arrayConcreteValueSerializer serialize an array/*array
@@ -113,14 +117,14 @@ type arrayConcreteValueSerializer struct {
113117
referencable bool
114118
}
115119

116-
func (s *arrayConcreteValueSerializer) WriteData(ctx *WriteContext, value reflect.Value) error {
120+
func (s *arrayConcreteValueSerializer) WriteData(ctx *WriteContext, value reflect.Value) {
117121
length := value.Len()
118122
buf := ctx.Buffer()
119123

120124
// Write length
121125
buf.WriteVaruint32(uint32(length))
122126
if length == 0 {
123-
return nil
127+
return
124128
}
125129

126130
// Determine collection flags - same logic as slices
@@ -173,7 +177,8 @@ func (s *arrayConcreteValueSerializer) WriteData(ctx *WriteContext, value reflec
173177
}
174178
if IsNamespacedType(TypeId(internalTypeID)) {
175179
if err := ctx.TypeResolver().WriteTypeInfo(buf, elemTypeInfo); err != nil {
176-
return err
180+
ctx.SetError(FromError(err))
181+
return
177182
}
178183
} else {
179184
buf.WriteVaruint32Small7(uint32(internalTypeID))
@@ -188,8 +193,9 @@ func (s *arrayConcreteValueSerializer) WriteData(ctx *WriteContext, value reflec
188193
// Handle null values (only for pointer element types)
189194
if hasNull && elem.IsNil() {
190195
if trackRefs {
191-
if err := s.elemSerializer.Write(ctx, RefModeTracking, false, elem); err != nil {
192-
return err
196+
s.elemSerializer.Write(ctx, RefModeTracking, false, elem)
197+
if ctx.HasError() {
198+
return
193199
}
194200
} else {
195201
buf.WriteInt8(NullFlag)
@@ -199,39 +205,47 @@ func (s *arrayConcreteValueSerializer) WriteData(ctx *WriteContext, value reflec
199205

200206
// Write element
201207
if trackRefs {
202-
if err := s.elemSerializer.Write(ctx, RefModeTracking, false, elem); err != nil {
203-
return err
208+
s.elemSerializer.Write(ctx, RefModeTracking, false, elem)
209+
if ctx.HasError() {
210+
return
204211
}
205212
} else {
206-
if err := s.elemSerializer.WriteData(ctx, elem); err != nil {
207-
return err
213+
s.elemSerializer.WriteData(ctx, elem)
214+
if ctx.HasError() {
215+
return
208216
}
209217
}
210218
}
211-
return nil
212219
}
213220

214-
func (s *arrayConcreteValueSerializer) Write(ctx *WriteContext, refMode RefMode, writeType bool, value reflect.Value) error {
215-
_, err := writeArrayRefAndType(ctx, refMode, writeType, value, -LIST)
216-
if err != nil {
217-
return err
221+
func (s *arrayConcreteValueSerializer) Write(ctx *WriteContext, refMode RefMode, writeType bool, value reflect.Value) {
222+
writeArrayRefAndType(ctx, refMode, writeType, value, -LIST)
223+
if ctx.HasError() {
224+
return
218225
}
219-
return s.WriteData(ctx, value)
226+
s.WriteData(ctx, value)
220227
}
221228

222-
func (s *arrayConcreteValueSerializer) ReadData(ctx *ReadContext, type_ reflect.Type, value reflect.Value) error {
229+
func (s *arrayConcreteValueSerializer) ReadData(ctx *ReadContext, type_ reflect.Type, value reflect.Value) {
223230
buf := ctx.Buffer()
224-
length := int(buf.ReadVaruint32())
231+
err := ctx.Err()
232+
length := int(buf.ReadVaruint32(err))
225233

226234
var trackRefs bool
227235
if length > 0 {
228236
// Read collection flags (same format as slices)
229-
collectFlag := buf.ReadInt8()
237+
collectFlag := buf.ReadInt8(err)
238+
if ctx.HasError() {
239+
return
240+
}
230241

231242
// Read element type info if present
232243
if (collectFlag & CollectionIsSameType) != 0 {
233244
if (collectFlag & CollectionIsDeclElementType) == 0 {
234-
typeID := buf.ReadVaruint32()
245+
typeID := buf.ReadVaruint32(err)
246+
if ctx.HasError() {
247+
return
248+
}
235249
// Read additional metadata for namespaced types
236250
_, _ = ctx.TypeResolver().readTypeInfoWithTypeID(buf, typeID)
237251
}
@@ -245,34 +259,32 @@ func (s *arrayConcreteValueSerializer) ReadData(ctx *ReadContext, type_ reflect.
245259

246260
// When tracking refs, the element serializer handles ref flags
247261
if trackRefs {
248-
if err := s.elemSerializer.Read(ctx, RefModeTracking, false, elem); err != nil {
249-
return err
250-
}
262+
s.elemSerializer.Read(ctx, RefModeTracking, false, elem)
251263
} else {
252-
if err := s.elemSerializer.ReadData(ctx, elem.Type(), elem); err != nil {
253-
return err
254-
}
264+
s.elemSerializer.ReadData(ctx, elem.Type(), elem)
265+
}
266+
if ctx.HasError() {
267+
return
255268
}
256269
}
257-
return nil
258270
}
259271

260-
func (s *arrayConcreteValueSerializer) Read(ctx *ReadContext, refMode RefMode, readType bool, value reflect.Value) error {
261-
done, err := readArrayRefAndType(ctx, refMode, readType, value)
262-
if done || err != nil {
263-
return err
272+
func (s *arrayConcreteValueSerializer) Read(ctx *ReadContext, refMode RefMode, readType bool, value reflect.Value) {
273+
done := readArrayRefAndType(ctx, refMode, readType, value)
274+
if done || ctx.HasError() {
275+
return
264276
}
265-
if err := s.ReadData(ctx, value.Type(), value); err != nil {
266-
return err
277+
s.ReadData(ctx, value.Type(), value)
278+
if ctx.HasError() {
279+
return
267280
}
268281
if refMode != RefModeNone {
269282
ctx.RefResolver().Reference(value)
270283
}
271-
return nil
272284
}
273285

274-
func (s *arrayConcreteValueSerializer) ReadWithTypeInfo(ctx *ReadContext, refMode RefMode, typeInfo *TypeInfo, value reflect.Value) error {
275-
return s.Read(ctx, refMode, false, value)
286+
func (s *arrayConcreteValueSerializer) ReadWithTypeInfo(ctx *ReadContext, refMode RefMode, typeInfo *TypeInfo, value reflect.Value) {
287+
s.Read(ctx, refMode, false, value)
276288
}
277289

278290
// arrayDynSerializer wraps sliceDynSerializer for arrays with interface element types.
@@ -289,26 +301,27 @@ func newArrayDynSerializer(elemType reflect.Type) (arrayDynSerializer, error) {
289301
return arrayDynSerializer{sliceSerializer: sliceSer}, nil
290302
}
291303

292-
func (s arrayDynSerializer) WriteData(ctx *WriteContext, value reflect.Value) error {
304+
func (s arrayDynSerializer) WriteData(ctx *WriteContext, value reflect.Value) {
293305
// Convert array to slice and forward to sliceDynSerializer
294306
slice := value.Slice(0, value.Len())
295-
return s.sliceSerializer.WriteData(ctx, slice)
307+
s.sliceSerializer.WriteData(ctx, slice)
296308
}
297309

298-
func (s arrayDynSerializer) Write(ctx *WriteContext, refMode RefMode, writeType bool, value reflect.Value) error {
299-
_, err := writeArrayRefAndType(ctx, refMode, writeType, value, LIST)
300-
if err != nil {
301-
return err
310+
func (s arrayDynSerializer) Write(ctx *WriteContext, refMode RefMode, writeType bool, value reflect.Value) {
311+
writeArrayRefAndType(ctx, refMode, writeType, value, LIST)
312+
if ctx.HasError() {
313+
return
302314
}
303-
return s.WriteData(ctx, value)
315+
s.WriteData(ctx, value)
304316
}
305317

306-
func (s arrayDynSerializer) ReadData(ctx *ReadContext, _ reflect.Type, value reflect.Value) error {
318+
func (s arrayDynSerializer) ReadData(ctx *ReadContext, _ reflect.Type, value reflect.Value) {
307319
// Create a temp slice to read into, then copy back to array
308320
sliceType := reflect.SliceOf(value.Type().Elem())
309321
tempSlice := reflect.MakeSlice(sliceType, value.Len(), value.Len())
310-
if err := s.sliceSerializer.ReadData(ctx, sliceType, tempSlice); err != nil {
311-
return err
322+
s.sliceSerializer.ReadData(ctx, sliceType, tempSlice)
323+
if ctx.HasError() {
324+
return
312325
}
313326
// Copy elements from temp slice to array
314327
copyLen := tempSlice.Len()
@@ -318,24 +331,23 @@ func (s arrayDynSerializer) ReadData(ctx *ReadContext, _ reflect.Type, value ref
318331
for i := 0; i < copyLen; i++ {
319332
value.Index(i).Set(tempSlice.Index(i))
320333
}
321-
return nil
322334
}
323335

324-
func (s arrayDynSerializer) Read(ctx *ReadContext, refMode RefMode, readType bool, value reflect.Value) error {
325-
done, err := readArrayRefAndType(ctx, refMode, readType, value)
326-
if done || err != nil {
327-
return err
336+
func (s arrayDynSerializer) Read(ctx *ReadContext, refMode RefMode, readType bool, value reflect.Value) {
337+
done := readArrayRefAndType(ctx, refMode, readType, value)
338+
if done || ctx.HasError() {
339+
return
328340
}
329-
return s.ReadData(ctx, value.Type(), value)
341+
s.ReadData(ctx, value.Type(), value)
330342
}
331343

332-
func (s arrayDynSerializer) ReadWithTypeInfo(ctx *ReadContext, refMode RefMode, typeInfo *TypeInfo, value reflect.Value) error {
333-
return s.Read(ctx, refMode, false, value)
344+
func (s arrayDynSerializer) ReadWithTypeInfo(ctx *ReadContext, refMode RefMode, typeInfo *TypeInfo, value reflect.Value) {
345+
s.Read(ctx, refMode, false, value)
334346
}
335347

336348
type byteArraySerializer struct{}
337349

338-
func (s byteArraySerializer) WriteData(ctx *WriteContext, value reflect.Value) error {
350+
func (s byteArraySerializer) WriteData(ctx *WriteContext, value reflect.Value) {
339351
buf := ctx.Buffer()
340352
length := value.Len()
341353
buf.WriteLength(length)
@@ -348,38 +360,40 @@ func (s byteArraySerializer) WriteData(ctx *WriteContext, value reflect.Value) e
348360
}
349361
buf.WriteBinary(data)
350362
}
351-
return nil
352363
}
353364

354-
func (s byteArraySerializer) Write(ctx *WriteContext, refMode RefMode, writeType bool, value reflect.Value) error {
355-
_, err := writeArrayRefAndType(ctx, refMode, writeType, value, BINARY)
356-
if err != nil {
357-
return err
365+
func (s byteArraySerializer) Write(ctx *WriteContext, refMode RefMode, writeType bool, value reflect.Value) {
366+
writeArrayRefAndType(ctx, refMode, writeType, value, BINARY)
367+
if ctx.HasError() {
368+
return
358369
}
359-
return s.WriteData(ctx, value)
370+
s.WriteData(ctx, value)
360371
}
361372

362-
func (s byteArraySerializer) ReadData(ctx *ReadContext, type_ reflect.Type, value reflect.Value) error {
373+
func (s byteArraySerializer) ReadData(ctx *ReadContext, type_ reflect.Type, value reflect.Value) {
363374
buf := ctx.Buffer()
364-
length := buf.ReadLength()
375+
err := ctx.Err()
376+
length := buf.ReadLength(err)
377+
if ctx.HasError() {
378+
return
379+
}
365380
data := make([]byte, length)
366381
buf.Read(data)
367382
if value.CanSet() {
368383
for i := 0; i < length && i < value.Len(); i++ {
369384
value.Index(i).SetUint(uint64(data[i]))
370385
}
371386
}
372-
return nil
373387
}
374388

375-
func (s byteArraySerializer) Read(ctx *ReadContext, refMode RefMode, readType bool, value reflect.Value) error {
376-
done, err := readArrayRefAndType(ctx, refMode, readType, value)
377-
if done || err != nil {
378-
return err
389+
func (s byteArraySerializer) Read(ctx *ReadContext, refMode RefMode, readType bool, value reflect.Value) {
390+
done := readArrayRefAndType(ctx, refMode, readType, value)
391+
if done || ctx.HasError() {
392+
return
379393
}
380-
return s.ReadData(ctx, value.Type(), value)
394+
s.ReadData(ctx, value.Type(), value)
381395
}
382396

383-
func (s byteArraySerializer) ReadWithTypeInfo(ctx *ReadContext, refMode RefMode, typeInfo *TypeInfo, value reflect.Value) error {
384-
return s.Read(ctx, refMode, false, value)
397+
func (s byteArraySerializer) ReadWithTypeInfo(ctx *ReadContext, refMode RefMode, typeInfo *TypeInfo, value reflect.Value) {
398+
s.Read(ctx, refMode, false, value)
385399
}

0 commit comments

Comments
 (0)