Improve variable marshalling

This commit is contained in:
David Vogel 2024-12-02 11:52:05 +01:00
parent c730d437ef
commit bff2664cfc
3 changed files with 34 additions and 6 deletions

View File

@ -8,7 +8,7 @@ import (
var stderrRegex = regexp.MustCompile(`^error: (?<error>.+)\n ┌─ (?<path>.+):(?<line>\d+):(?<column>\d+)\n`) var stderrRegex = regexp.MustCompile(`^error: (?<error>.+)\n ┌─ (?<path>.+):(?<line>\d+):(?<column>\d+)\n`)
// Error represents a typst error. // Error represents a generic typst error.
type Error struct { type Error struct {
Inner error Inner error

View File

@ -4,6 +4,7 @@ import (
"encoding" "encoding"
"fmt" "fmt"
"io" "io"
"math"
"reflect" "reflect"
"slices" "slices"
"strconv" "strconv"
@ -44,7 +45,9 @@ func (e *VariableEncoder) WriteIndentationCharacters() {
func (e *VariableEncoder) marshal(v reflect.Value) error { func (e *VariableEncoder) marshal(v reflect.Value) error {
if !v.IsValid() { if !v.IsValid() {
return fmt.Errorf("invalid reflect.Value %v", v) e.WriteString("none")
return nil
//return fmt.Errorf("invalid reflect.Value %v", v)
} }
t := v.Type() t := v.Type()
@ -89,14 +92,24 @@ func (e *VariableEncoder) marshal(v reflect.Value) error {
e.WriteString(strconv.FormatInt(v.Int(), 10)) e.WriteString(strconv.FormatInt(v.Int(), 10))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
e.WriteString(strconv.FormatUint(v.Uint(), 10)) e.WriteString(strconv.FormatUint(v.Uint(), 10))
case reflect.Float32: case reflect.Float32, reflect.Float64:
e.WriteString(strconv.FormatFloat(v.Float(), 'e', -1, 32)) f := v.Float()
case reflect.Float64: switch {
e.WriteString(strconv.FormatFloat(v.Float(), 'e', -1, 64)) case math.IsNaN(f):
e.WriteString("float.nan")
case math.IsInf(f, 1):
e.WriteString("float.inf")
case math.IsInf(f, -1):
e.WriteString("-float.inf")
default:
e.WriteString(strconv.FormatFloat(f, 'e', -1, 64))
}
case reflect.String: case reflect.String:
return e.encodeString(v) return e.encodeString(v)
case reflect.Interface, reflect.Pointer: case reflect.Interface, reflect.Pointer:
return e.marshal(v.Elem()) return e.marshal(v.Elem())
case reflect.Map:
return e.encodeMap(v)
case reflect.Struct: case reflect.Struct:
return e.encodeStruct(v, t) return e.encodeStruct(v, t)
case reflect.Slice: case reflect.Slice:
@ -141,6 +154,11 @@ func (e *VariableEncoder) encodeString(v reflect.Value) error {
} }
func (e *VariableEncoder) encodeStruct(v reflect.Value, t reflect.Type) error { func (e *VariableEncoder) encodeStruct(v reflect.Value, t reflect.Type) error {
if v.NumField() == 0 {
e.WriteString("()")
return nil
}
e.WriteString("(\n") e.WriteString("(\n")
e.indentLevel++ e.indentLevel++
@ -187,6 +205,11 @@ func (e *VariableEncoder) resolveKeyName(v reflect.Value) (string, error) {
} }
func (e *VariableEncoder) encodeMap(v reflect.Value) error { func (e *VariableEncoder) encodeMap(v reflect.Value) error {
if v.Len() == 0 {
e.WriteString("()")
return nil
}
e.WriteString("(\n") e.WriteString("(\n")
e.indentLevel++ e.indentLevel++

View File

@ -39,10 +39,15 @@ func TestVariableEncoder(t *testing.T) {
Foo string Foo string
Bar int Bar int
}{"Hey!", 12345}, false, "(\n Foo: \"Hey!\",\n Bar: 12345,\n)"}, }{"Hey!", 12345}, false, "(\n Foo: \"Hey!\",\n Bar: 12345,\n)"},
{"struct empty", struct{}{}, false, "()"},
{"struct empty pointer", (*struct{})(nil), false, "none"},
{"map string string", map[string]string{"Foo": "Bar", "Foo2": "Electric Foogaloo"}, false, "(\n Foo: \"Bar\",\n Foo2: \"Electric Foogaloo\",\n)"}, {"map string string", map[string]string{"Foo": "Bar", "Foo2": "Electric Foogaloo"}, false, "(\n Foo: \"Bar\",\n Foo2: \"Electric Foogaloo\",\n)"},
{"map string string empty", map[string]string{}, false, "()"},
{"map string string nil", map[string]string(nil), false, "()"}, {"map string string nil", map[string]string(nil), false, "()"},
{"string array", [5]string{"Foo", "Bar"}, false, `("Foo", "Bar", "", "", "")`}, {"string array", [5]string{"Foo", "Bar"}, false, `("Foo", "Bar", "", "", "")`},
{"string slice", []string{"Foo", "Bar"}, false, `("Foo", "Bar")`}, {"string slice", []string{"Foo", "Bar"}, false, `("Foo", "Bar")`},
{"string slice empty", []string{}, false, `()`},
{"string slice nil", []string(nil), false, `()`},
{"string slice pointer", &[]string{"Foo", "Bar"}, false, `("Foo", "Bar")`}, {"string slice pointer", &[]string{"Foo", "Bar"}, false, `("Foo", "Bar")`},
} }
for _, tt := range tests { for _, tt := range tests {