Skip to content

Commit

Permalink
fix: Pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
romshark committed Mar 5, 2024
1 parent c91d1c5 commit 1b2c8eb
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 19 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Roadmap:
- [x] Primitive types
- [x] Struct types
- [x] Type `struct{}`
- [ ] Recursive struct types
- [x] Recursive struct types
- [x] Slices
- [x] Arrays
- [x] Type `any`
Expand Down
101 changes: 88 additions & 13 deletions jscandec.go
Original file line number Diff line number Diff line change
Expand Up @@ -1189,7 +1189,6 @@ func (d *Decoder[S, T]) Decode(s S, t *T, options *DecodeOptions) (err ErrorDeco

si := uint32(0)
d.stackExp[0].Dest = unsafe.Pointer(t)
// fmt.Printf("VROOT %p\n", d.stackExp[0].Dest)

errTok := d.tokenizer.Tokenize(s, func(tokens []jscan.Token[S]) (exit bool) {
// ti stands for the token index and points at the current token
Expand All @@ -1208,8 +1207,7 @@ func (d *Decoder[S, T]) Decode(s S, t *T, options *DecodeOptions) (err ErrorDeco
*(*unsafe.Pointer)(p) = dp
}
continue
case ExpectTypePtrRecur:
panic("TODO")

case ExpectTypeJSONUnmarshaler:
goto ON_JSON_UNMARSHALER
}
Expand Down Expand Up @@ -1875,6 +1873,8 @@ func (d *Decoder[S, T]) Decode(s S, t *T, options *DecodeOptions) (err ErrorDeco
// Skip
case ExpectTypeStruct, ExpectTypeStructRecur:
// Skip
case ExpectTypePtr, ExpectTypePtrRecur:
*(*unsafe.Pointer)(p) = nil
case ExpectTypeBool:
*(*bool)(p) = zeroBool
case ExpectTypeStr:
Expand Down Expand Up @@ -2841,6 +2841,52 @@ func (d *Decoder[S, T]) Decode(s S, t *T, options *DecodeOptions) (err ErrorDeco
ti = len(tokens) - len(tail)
goto ON_VAL_END

case ExpectTypePtrRecur:
p := unsafe.Pointer(
uintptr(d.stackExp[si].Dest) + d.stackExp[si].Offset,
)

siPointer := si
si = uint32(d.stackExp[si].CapOrRecurFrame)
// Push recursion stack
// fmt.Printf("%d\tPUSH STACK %p OFFSET %d SI %d\n",
// ti,
// d.stackExp[si].Dest,
// d.stackExp[si].Offset,
// si)
d.stackExp[si].RecursionStack = append(
d.stackExp[si].RecursionStack, recursionStackFrame{
Dest: d.stackExp[si].Dest,
Offset: d.stackExp[si].Offset,
ContainerFrame: siPointer,
},
)
// fmt.Printf("%d\tRECSTACK: %v\n", ti, d.stackExp[si].RecursionStack)

var dp unsafe.Pointer
if *(*unsafe.Pointer)(p) != nil {
dp = *(*unsafe.Pointer)(p)
// fmt.Printf("%d\tJUST SET %p\n", ti, dp)
} else {
dp = allocate(d.stackExp[si].Size)
// fmt.Printf(
// "%d\tALLOCATED NEW INSTANCE %p SIZE %d SET SI %d WRITE AT %p OFFSET %d\n",
// ti, dp, d.stackExp[si].Size, si, d.stackExp[si].Dest, d.stackExp[si].Offset)
*(*unsafe.Pointer)(p) = dp
}
d.stackExp[si].Dest = dp

if tokens[ti].Elements == 0 {
ti += 2
goto ON_RECUR_OBJ_END
}
// Point all fields to the struct, the offsets are already
// set statically during decoder init time.
for i := range d.stackExp[si].Fields {
d.stackExp[d.stackExp[si].Fields[i].FrameIndex].Dest = dp
}
ti++

case ExpectTypeMapRecur:
// Push recursion stack
recursiveFrame := d.stackExp[si].CapOrRecurFrame
Expand All @@ -2863,7 +2909,7 @@ func (d *Decoder[S, T]) Decode(s S, t *T, options *DecodeOptions) (err ErrorDeco
*(*unsafe.Pointer)(p) = makemap(
d.stackExp[si].MapType, tokens[ti].Elements,
)
// fmt.Printf("INIT MAP %p TO %p OFFSET %d\n",
// fmt.Printf("🌈 INIT MAP %p TO %p OFFSET %d\n",
// *(*unsafe.Pointer)(p), d.stackExp[si].Dest, d.stackExp[si].Offset)
}
if tokens[ti].Elements == 0 {
Expand Down Expand Up @@ -3015,7 +3061,7 @@ func (d *Decoder[S, T]) Decode(s S, t *T, options *DecodeOptions) (err ErrorDeco

key := s[tokens[ti].Index+1 : tokens[ti].End-1]

// fmt.Printf("KEY %q SI %d ON %p\n", key, si, d.stackExp[si].Dest)
// fmt.Printf("\nKEY %q SI %d ON %p\n", key, si, d.stackExp[si].Dest)

typMap := d.stackExp[si].MapType
typVal := d.stackExp[si].MapValueType
Expand Down Expand Up @@ -3284,7 +3330,7 @@ func (d *Decoder[S, T]) Decode(s S, t *T, options *DecodeOptions) (err ErrorDeco
ti++

case jscan.TokenTypeObjectEnd:
// fmt.Printf("OBJ END TI %d SI %d\n", ti, si)
// fmt.Printf("%d\tOBJ END SI %d\n", ti, si)
ti++
switch d.stackExp[si].Type {
case ExpectTypeStruct:
Expand All @@ -3296,7 +3342,7 @@ func (d *Decoder[S, T]) Decode(s S, t *T, options *DecodeOptions) (err ErrorDeco
recurStack := d.stackExp[recursiveFrame].RecursionStack
if len(recurStack) < 1 {
// In map of the root recursive struct
// si = uint32(d.stackExp[si].CapOrRecurFrame)
si = uint32(d.stackExp[si].CapOrRecurFrame)
// fmt.Printf("%d\tIN ROOT MAP\n", ti)
goto ON_VAL_END
}
Expand Down Expand Up @@ -3357,15 +3403,44 @@ func (d *Decoder[S, T]) Decode(s S, t *T, options *DecodeOptions) (err ErrorDeco

ON_RECUR_OBJ_END:
if l := len(d.stackExp[si].RecursionStack); l > 0 {
siCon := d.stackExp[si].RecursionStack[l-1].ContainerFrame
// fmt.Printf("%d\tRECOBJ END\tSI %d CONTAINER %d\n",
// ti, si, siCon)
switch d.stackExp[siCon].Type {
top := d.stackExp[si].RecursionStack[l-1]
// fmt.Printf("%d\tRECOBJ END\tSI %d TOPDEST %p CONTAINER %d\n",
// ti, si, top.Dest, top.ContainerFrame)
switch d.stackExp[top.ContainerFrame].Type {
case ExpectTypeSliceRecur:
d.stackExp[si].Offset += d.stackExp[si].Size
case ExpectTypePtrRecur:
recurStack := d.stackExp[si].RecursionStack
if len(recurStack) < 1 {
// In map of the root recursive struct
// fmt.Printf("%d\tIN ROOT STRUCT\n", ti)
goto ON_VAL_END
}

// Reset to parent context
// dumpStack("BEFORE RESET")
topIndex := len(recurStack) - 1
d.stackExp[si].Dest = top.Dest
d.stackExp[si].Offset = top.Offset
fields := d.stackExp[si].Fields
for i := range fields {
d.stackExp[fields[i].FrameIndex].Dest = top.Dest
}

// Pop recursion stack
recurStack[topIndex].Dest = nil
d.stackExp[si].RecursionStack = recurStack[:topIndex]

si = uint32(d.stackExp[top.ContainerFrame].ParentFrameIndex)
// fmt.Println("EXITED POINTER-RECURSIVE STRUCT", si)
// dumpStack("AFTER RESET")

case ExpectTypeMapRecur:
si = siCon
// fmt.Println("BACK TO RECUR MAP", si)
si = top.ContainerFrame
// Set the top stack destination so the next key gets assigned to it.
// Otherwise we'll be in the destination of the previously assigned
// key, which will point to an empty map.
d.stackExp[si].Dest = top.Dest
}
continue
}
Expand Down
100 changes: 95 additions & 5 deletions jscandec_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,18 @@ func TestAppendTypeToStack(t *testing.T) {
type SStringUint64 struct {
Uint64 uint64 `json:",string"`
}
type SRecurSlice struct {
ID string
Recursion []SRecurSlice
}
type SRecurMap struct {
ID string
Recursion map[string]SRecurMap
}
type SRecurPtr struct {
ID string
Recursion *SRecurPtr
}

tpS3 := reflect.TypeOf(S3{})
tpS4 := reflect.TypeOf(S4{})
Expand Down Expand Up @@ -1345,18 +1354,64 @@ func TestAppendTypeToStack(t *testing.T) {
},
},
{
Input: SRecurMap{},
Input: []SRecurSlice{},
ExpectStack: []stackFrame[string]{
{
Type: ExpectTypeSlice,
Size: reflect.TypeOf([]SRecurSlice{}).Size(),
ParentFrameIndex: noParentFrame,
},
{
Type: ExpectTypeStructRecur,
RType: reflect.TypeOf(SRecurMap{}),
RType: reflect.TypeOf(SRecurSlice{}),
Fields: []fieldStackFrame{
{FrameIndex: 1, Name: "Recursion"},
{FrameIndex: 2, Name: "ID"},
{FrameIndex: 3, Name: "Recursion"},
},
RecursionStack: make([]recursionStackFrame, 0, 64),
Size: reflect.TypeOf(SStringUint64{}).Size(),
Size: reflect.TypeOf(SRecurSlice{}).Size(),
ParentFrameIndex: 0,
},
{
Type: ExpectTypeStr,
Size: reflect.TypeOf(string("")).Size(),
Offset: reflect.TypeOf(SRecurSlice{}).Field(0).Offset,
ParentFrameIndex: 1,
},
{
Type: ExpectTypeSliceRecur,
Size: reflect.TypeOf([]SRecurSlice{}).Size(),
Offset: reflect.TypeOf(SRecurSlice{}).Field(1).Offset,
CapOrRecurFrame: 1,
ParentFrameIndex: 1,
},
},
},
{
Input: []SRecurMap{},
ExpectStack: []stackFrame[string]{
{
Type: ExpectTypeSlice,
Size: reflect.TypeOf([]SRecurMap{}).Size(),
ParentFrameIndex: noParentFrame,
},
{
Type: ExpectTypeStructRecur,
RType: reflect.TypeOf(SRecurMap{}),
Fields: []fieldStackFrame{
{FrameIndex: 2, Name: "ID"},
{FrameIndex: 3, Name: "Recursion"},
},
RecursionStack: make([]recursionStackFrame, 0, 64),
Size: reflect.TypeOf(SRecurMap{}).Size(),
ParentFrameIndex: 0,
},
{
Type: ExpectTypeStr,
Size: reflect.TypeOf(string("")).Size(),
Offset: reflect.TypeOf(SRecurMap{}).Field(0).Offset,
ParentFrameIndex: 1,
},
{
Type: ExpectTypeMapRecur,
MapType: getTyp(reflect.TypeOf(
Expand All @@ -1369,12 +1424,47 @@ func TestAppendTypeToStack(t *testing.T) {
Size: reflect.TypeOf(
map[string]SRecurMap{},
).Size(),
CapOrRecurFrame: 0,
Offset: reflect.TypeOf(SRecurMap{}).Field(1).Offset,
CapOrRecurFrame: 1,
ParentFrameIndex: 1,
},
{
Type: ExpectTypeStr,
Size: reflect.TypeOf(string("")).Size(),
ParentFrameIndex: 3,
},
},
},
{
Input: []SRecurPtr{},
ExpectStack: []stackFrame[string]{
{
Type: ExpectTypeSlice,
Size: reflect.TypeOf([]SRecurPtr{}).Size(),
ParentFrameIndex: noParentFrame,
},
{
Type: ExpectTypeStructRecur,
RType: reflect.TypeOf(SRecurPtr{}),
Fields: []fieldStackFrame{
{FrameIndex: 2, Name: "ID"},
{FrameIndex: 3, Name: "Recursion"},
},
RecursionStack: make([]recursionStackFrame, 0, 64),
Size: reflect.TypeOf(SRecurPtr{}).Size(),
ParentFrameIndex: 0,
},
{
Type: ExpectTypeStr,
Size: reflect.TypeOf(string("")).Size(),
Offset: reflect.TypeOf(SRecurPtr{}).Field(0).Offset,
ParentFrameIndex: 1,
},
{
Type: ExpectTypePtrRecur,
Size: reflect.TypeOf((*SRecurPtr)(nil)).Size(),
Offset: reflect.TypeOf(SRecurPtr{}).Field(1).Offset,
CapOrRecurFrame: 1,
ParentFrameIndex: 1,
},
},
Expand Down
Loading

0 comments on commit 1b2c8eb

Please sign in to comment.