rlp: allow manually registering types implementing Encoder/Decoder

in tinygo
This commit is contained in:
Ömer Faruk IRMAK 2025-06-16 17:06:11 +03:00
parent e2007e513c
commit 0af0aa74ce
5 changed files with 70 additions and 7 deletions

View file

@ -168,7 +168,7 @@ func makeDecoder(typ reflect.Type, tags rlpstruct.Tags) (dec decoder, err error)
return decodeU256NoPtr, nil return decodeU256NoPtr, nil
case kind == reflect.Ptr: case kind == reflect.Ptr:
return makePtrDecoder(typ, tags) return makePtrDecoder(typ, tags)
case reflect.PointerTo(typ).Implements(decoderInterface): case implementsInterface(reflect.PointerTo(typ), decoderInterface):
return decodeDecoder, nil return decodeDecoder, nil
case isUint(kind): case isUint(kind):
return decodeUint, nil return decodeUint, nil
@ -262,7 +262,7 @@ func decodeU256(s *Stream, val reflect.Value) error {
func makeListDecoder(typ reflect.Type, tag rlpstruct.Tags) (decoder, error) { func makeListDecoder(typ reflect.Type, tag rlpstruct.Tags) (decoder, error) {
etype := typ.Elem() etype := typ.Elem()
if etype.Kind() == reflect.Uint8 && !reflect.PointerTo(etype).Implements(decoderInterface) { if etype.Kind() == reflect.Uint8 && !implementsInterface(reflect.PointerTo(etype), decoderInterface) {
if typ.Kind() == reflect.Array { if typ.Kind() == reflect.Array {
return decodeByteArray, nil return decodeByteArray, nil
} }

View file

@ -151,7 +151,7 @@ func makeWriter(typ reflect.Type, ts rlpstruct.Tags) (writer, error) {
return writeU256IntNoPtr, nil return writeU256IntNoPtr, nil
case kind == reflect.Ptr: case kind == reflect.Ptr:
return makePtrWriter(typ, ts) return makePtrWriter(typ, ts)
case reflect.PointerTo(typ).Implements(encoderInterface): case implementsInterface(reflect.PointerTo(typ), encoderInterface):
return makeEncoderWriter(typ), nil return makeEncoderWriter(typ), nil
case isUint(kind): case isUint(kind):
return writeUint, nil return writeUint, nil
@ -409,7 +409,7 @@ func makePtrWriter(typ reflect.Type, ts rlpstruct.Tags) (writer, error) {
} }
func makeEncoderWriter(typ reflect.Type) writer { func makeEncoderWriter(typ reflect.Type) writer {
if typ.Implements(encoderInterface) { if implementsInterface(typ, encoderInterface) {
return func(val reflect.Value, w *encBuffer) error { return func(val reflect.Value, w *encBuffer) error {
return val.Interface().(Encoder).EncodeRLP(w) return val.Interface().(Encoder).EncodeRLP(w)
} }

25
rlp/reflection.go Normal file
View file

@ -0,0 +1,25 @@
// Copyright 2025 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
//go:build !tinygo
package rlp
import "reflect"
func implementsInterface(t reflect.Type, i reflect.Type) bool {
return t.Implements(i)
}

38
rlp/reflection_tinygo.go Normal file
View file

@ -0,0 +1,38 @@
// Copyright 2025 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
//go:build tinygo
package rlp
import "reflect"
var customEncodedTypes = make(map[reflect.Type]bool)
func implementsInterface(t reflect.Type, i reflect.Type) bool {
// reflect implementation of tinygo cannot handle this automatically
// at runtime. So we need custom encoded types to be registered manually.
if i == decoderInterface || i == encoderInterface {
return customEncodedTypes[t]
}
return false
}
// RegisterCustomEncodedType manually registers a type as an implementation of
// Decoder and Encoder interfaces
func RegisterCustomEncodedType(t reflect.Type) {
customEncodedTypes[t] = true
}

View file

@ -199,8 +199,8 @@ func rtypeToStructType(typ reflect.Type, rec map[reflect.Type]*rlpstruct.Type) *
t := &rlpstruct.Type{ t := &rlpstruct.Type{
Name: typ.String(), Name: typ.String(),
Kind: k, Kind: k,
IsEncoder: typ.Implements(encoderInterface), IsEncoder: implementsInterface(typ, encoderInterface),
IsDecoder: typ.Implements(decoderInterface), IsDecoder: implementsInterface(typ, decoderInterface),
} }
rec[typ] = t rec[typ] = t
if k == reflect.Array || k == reflect.Slice || k == reflect.Ptr { if k == reflect.Array || k == reflect.Slice || k == reflect.Ptr {
@ -234,5 +234,5 @@ func isUint(k reflect.Kind) bool {
} }
func isByte(typ reflect.Type) bool { func isByte(typ reflect.Type) bool {
return typ.Kind() == reflect.Uint8 && !typ.Implements(encoderInterface) return typ.Kind() == reflect.Uint8 && !implementsInterface(typ, encoderInterface)
} }