Skip to content

Commit

Permalink
Wrap reflect.Type.ConvertibleTo calls with Go/TinyGo implementations
Browse files Browse the repository at this point in the history
Enable package to be usable with [TinyGo](https://tinygo.org).

Changes calls to reflect.Type.ConvertibleTo in decode.go to Go/TinyGo
specific implementations. Basic examples work, but (some) unit tests
fail as conversions to `interface{}` do not currently work in TinyGo.

Otherwise, all other functionality I've tested now appears to work
properly: highlighted error output, `cmd/ycat`, the README.md examples,
etc.

As an example, both Go and TinyGo are now able to use this package
vis-a-vis this example taken from README.md:

```go
package main

import (
	"fmt"
	"strings"

	"github.com/goccy/go-yaml"
)

func main() {
	yml := `
store:
  book:
    - author: john
      price: 10
    - author: ken
      price: 12
  bicycle:
    color: red
    price: 19.95
`
	path, err := yaml.PathString("$.store.book[*].author")
	if err != nil {
		//...
	}
	var authors []string
	if err := path.Read(strings.NewReader(yml), &authors); err != nil {
		//...
	}
	fmt.Println(authors)
}
```

Output:

```sh
ken@ken-desktop:~/g$ go run main.go
[john ken]
ken@ken-desktop:~/g$ tinygo run main.go
[john ken]
ken@ken-desktop:~/g$
```

(previously the `tinygo run` would panic)
  • Loading branch information
kenshaw committed Nov 17, 2024
1 parent ff5d41f commit e1eea91
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 6 deletions.
11 changes: 11 additions & 0 deletions conv_go.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//go:build !tinygo

package yaml

import (
"reflect"
)

func convertibleTo(src reflect.Value, typ reflect.Type) bool {
return src.Type().ConvertibleTo(typ)
}
65 changes: 65 additions & 0 deletions conv_tinygo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//go:build tinygo

package yaml

import (
"reflect"
)

func convertibleTo(src reflect.Value, typ reflect.Type) bool {
srck, typk := src.Kind(), typ.Kind()
if srck == typk {
return true
}
switch srck {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch typk {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return true
case reflect.Float32, reflect.Float64:
return true
case reflect.String:
return true
}

case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
switch typk {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return true
case reflect.Float32, reflect.Float64:
return true
case reflect.String:
return true
}

case reflect.Float32, reflect.Float64:
switch typk {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return true
case reflect.Float32, reflect.Float64:
return true
}

case reflect.Slice:
if typk == reflect.String /*&& !src.Type().Elem().isNamed()*/ {
switch src.Type().Elem().Kind() {
case reflect.Uint8, reflect.Int32:
return true
}
}

case reflect.String:
switch typk {
case reflect.Slice:
switch typ.Elem().Kind() {
case reflect.Uint8, reflect.Int32:
return true
}
return false
}
}

return false
}
10 changes: 4 additions & 6 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ func (d *Decoder) getArrayNode(node ast.Node) (ast.ArrayNode, error) {

func (d *Decoder) convertValue(v reflect.Value, typ reflect.Type, src ast.Node) (reflect.Value, error) {
if typ.Kind() != reflect.String {
if !v.Type().ConvertibleTo(typ) {
if !convertibleTo(v, typ) {

// Special case for "strings -> floats" aka scientific notation
// If the destination type is a float and the source type is a string, check if we can
Expand Down Expand Up @@ -613,7 +613,7 @@ func (d *Decoder) convertValue(v reflect.Value, typ reflect.Type, src ast.Node)
case reflect.Bool:
return reflect.ValueOf(fmt.Sprint(v.Bool())), nil
}
if !v.Type().ConvertibleTo(typ) {
if !convertibleTo(v, typ) {
return reflect.Zero(typ), errors.ErrTypeMismatch(typ, v.Type(), src.GetToken())
}
return v.Convert(typ), nil
Expand Down Expand Up @@ -868,9 +868,7 @@ func (d *Decoder) decodeByUnmarshaler(ctx context.Context, dst reflect.Value, sr
return fmt.Errorf("does not implemented Unmarshaler")
}

var (
astNodeType = reflect.TypeOf((*ast.Node)(nil)).Elem()
)
var astNodeType = reflect.TypeOf((*ast.Node)(nil)).Elem()

func (d *Decoder) decodeValue(ctx context.Context, dst reflect.Value, src ast.Node) error {
if src.Type() == ast.AnchorType {
Expand Down Expand Up @@ -1634,7 +1632,7 @@ func (d *Decoder) decodeMap(ctx context.Context, dst reflect.Value, src ast.Node
return err
}
k = reflect.ValueOf(keyVal)
if k.IsValid() && k.Type().ConvertibleTo(keyType) {
if k.IsValid() && convertibleTo(k, keyType) {
k = k.Convert(keyType)
}
}
Expand Down

0 comments on commit e1eea91

Please sign in to comment.