Aphoh / go-substrate-gen

https://github.com/Aphoh/go-substrate-gen

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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
}