Skip to content

Commit

Permalink
clean up and add notes
Browse files Browse the repository at this point in the history
  • Loading branch information
racytech committed Jan 15, 2025
1 parent 0c9209d commit 4428ec0
Show file tree
Hide file tree
Showing 7 changed files with 929 additions and 202 deletions.
5 changes: 5 additions & 0 deletions cmd/rlpgen/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,30 @@ var decodeBufAdded bool
var intSizeAdded bool // for encoding size
var intEncodeAdded bool // for rlp encoding

// create decoder buffer if not added yet
func addDecodeBuf(b *bytes.Buffer) {
if !decodeBufAdded {
fmt.Fprint(b, " var b []byte\n")
decodeBufAdded = true
}
}

// add List start check
func startListDecode(b *bytes.Buffer, fieldName string) {
fmt.Fprintf(b, " _, err = s.List()\n")
fmt.Fprintf(b, " if err != nil {\n")
fmt.Fprintf(b, " return fmt.Errorf(\"error decoding field %s - expected list start, err: %%w\", err)\n", fieldName)
fmt.Fprintf(b, " }\n")
}

// add List end check
func endListDecode(b *bytes.Buffer, fieldName string) {
fmt.Fprintf(b, " if err = s.ListEnd(); err != nil {\n")
fmt.Fprintf(b, " return fmt.Errorf(\"error decoding field %s - fail to close list, err: %%w\", err)\n", fieldName)
fmt.Fprintf(b, " }\n")
}

// add reusable int for encoding size usage
func addIntSize(b *bytes.Buffer) {
if !intSizeAdded {
fmt.Fprint(b, " gidx := 0\n")
Expand All @@ -39,6 +43,7 @@ func addIntSize(b *bytes.Buffer) {
}
}

// add reusable int for encoding usage
func addIntEncode(b *bytes.Buffer) {
if !intEncodeAdded {
fmt.Fprint(b, " gidx := 0\n")
Expand Down
69 changes: 62 additions & 7 deletions cmd/rlpgen/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// NOTE: This generator works only on structures, if the type is slice of types (e.g []MyType) it will fail.
// And not all the field types currently supported, see `matcher.go`
// This will be fixed in the future.

package main

import (
Expand Down Expand Up @@ -202,14 +206,65 @@ func addEncodeLogic(b1, b2, b3 *bytes.Buffer, named *types.Named) error {

matchStrTypeToFunc(strTyp)(b1, b2, b3, _struct.Field(i).Type(), _struct.Field(i).Name())
}
} else { // user named types that are not structs, could be:
// 1. type aliases
// - type aliases for basic types, e.g type MyInt int
// - type aliases for user named types, e.g type MyHash common.Hash (could be struct as well!)
// 2. slice types
// - slice of basice types, e.g type MyInts []int
// - slice of user named types, e.g type ReceiptsForStorage []*ReceiptForStorage
} else {

Check failure on line 209 in cmd/rlpgen/main.go

View workflow job for this annotation

GitHub Actions / lint

SA9003: empty branch (staticcheck)

// TODO(racytech): see handleType
}

return nil
}

func handleType(t types.Type, caller types.Type, depth int, ptr bool) {
switch e := t.(type) {
case *types.Pointer:
// check if double pointer, fail if depth > 0 and ptr == true

// if t is Pointer type pass to the next level
handleType(e.Elem(), e, depth+1, true)
case *types.Named:
// if t is user named type,
// check if big.Int or uint256.Int -> check if pointer -> encode/decode accordingly -> return
// check if rlp generated for this type -> if yes remove the file
// else pass to the next level
handleType(e.Underlying(), e, depth+1, false)
// if underlying is a struct
// check if rlp generated for this type -> if yes call RLP encode/decode methods on it, return
case *types.Basic:
// check if caller Named (e.g type MyInt int) -> TODO
// check if caller Slice or Array
// if t is byte slice or byte array -> encode -> return
// check if caller Pointer -> encode -> return
//
// or if caller is nil -> call rlp encoding function on basic types, bool, uint, int etc.
// return
case *types.Slice:
// check if it's simple byteslice
// if yes call RLP encode/decode methods on it, return
// check if it's slice of named types. e.g []common.Hash -> [][32]byte, or type MyStruct struct {a, b, c}
// ^TODO think about this case^
//
handleType(e.Elem(), e, depth+1, false)
case *types.Array:
// check if it's simple bytearray
// if yes call RLP encode/decode methods on it, return
// check if it's slice of named types. e.g [10]common.Hash -> [10][32]byte, or type MyStruct struct {a, b, c}
// ^TODO think about this case^
//
handleType(e.Elem(), e, depth+1, false)
case *types.Struct:
// check if nested struct
// if yes check if rlp previously generated for this type -> if yes remove the file
// try generating rlp for this structure, e.g as follows:
// process(t) -> if successful
// add encoding/decoding logic of this struct to the buffers
// return

// else -> top level call
for i := 0; i < e.NumFields(); i++ {
// this should panic and fail generating everything in case of error
handleType(e.Field(i).Type(), e, depth+1, false)
}
default:
panic("unhandled")
}
}
5 changes: 5 additions & 0 deletions cmd/rlpgen/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import (
"go/types"
)

// handle should write encoding size of type as well as encoding and decoding logic for the type
type handle func(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string)

// func foofunc(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) {}

// all possible types that this generator can handle for the time being.
// to add a new type add a string representation of type here and write the handle function for it in the `handlers.go`
var handlers = map[string]handle{
"uint64": uintHandle,
"*uint64": uintPtrHandle,
Expand Down Expand Up @@ -39,6 +42,7 @@ var handlers = map[string]handle{
"*[n]byte": byteArrayPtrHandle,
}

// recursive function, constructs string representation of a type. array represented as [n]
func matchTypeToString(fieldType types.Type, in string) string {
if named, ok := fieldType.(*types.Named); ok {
return in + named.Obj().Pkg().Name() + "." + named.Obj().Name()
Expand All @@ -55,6 +59,7 @@ func matchTypeToString(fieldType types.Type, in string) string {
}
}

// matches string representation of a type to a corresponding function
func matchStrTypeToFunc(strType string) handle {
switch strType {
case "int16", "int32", "int", "int64", "uint16", "uint32", "uint", "uint64":
Expand Down
Loading

0 comments on commit 4428ec0

Please sign in to comment.