Encode variants like Rust for maximal space-efficiency
naterarmstrong opened this issue · comments
Currently, go-substrate-gen
encodes variants pretty inefficiently by having an empty entry in every variant struct. This could be solved by having methods that return a struct containing each variant's information, and only storing a uint8
and the actual information of the variant in go
. It would look something like the below (omitting the err != nil
checks for brevity)
type VariantXYZ struct {
index uint8
data interface{}
}
func (ty VariantXYZ) Encode(encoder scale.Encoder) (err error) {
err = encoder.PushByte(ty.index)
switch ty.index {
case 0:
err = encode.Encode(ty.data.(X))
return err
case 1:
err = encode.Encode(ty.data.(Y))
return err
case 2:
err = encode.Encode(ty.data.(Z))
return err
}
return fmt.Errorf("Unrecognized variant")
}
func (ty *VariantXYZ) Decode(decoder scale.Decoder) (err error) {
variant, err := decoder.ReadOneByte()
ty.variant = variant
switch variant {
case 0:
var tmp X
err = decoder.Decode(&tmp)
ty.data = &tmp
return
case 1:
var tmp Y
err = decoder.Decode(&tmp)
ty.data = &tmp
return
case 2:
var tmp Z
err = decoder.Decode(&tmp)
ty.data = &tmp
return
}
}
func (ty *VariantXYZ) IsX() bool {
return ty.index == 0
}
func (ty *VariantXYZ) IsY() bool {
return ty.index == 1
}
func (ty *VariantXYZ) IsZ() bool {
return ty.index == 2
}
// Optionally these could just use go semantics and return the zero struct if it fails for easier chaining
func (ty *VariantXYZ) X() (d X, err error) {
if !ty.IsX() {
err = fmt.Errorf("Variant is not X")
}
return ty.data.(X), nil
}
func (ty *VariantXYZ) Y() (d Y, err error) {
if !ty.IsY() {
err = fmt.Errorf("Variant is not Y")
}
return ty.data.(Y), nil
}
func (ty *VariantXYZ) X() (d Z, err error) {
if !ty.IsZ() {
err = fmt.Errorf("Variant is not Z")
}
return ty.data.(X), nil
}