Skip to content

Commit

Permalink
cue: support decoding into cue.Value fields
Browse files Browse the repository at this point in the history
Fixes #2029.

Signed-off-by: Roger Peppe <[email protected]>
Change-Id: Ibe178f5428b2e97b04a1af9d9d9b631fea0a604c
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/547369
TryBot-Result: CUEcueckoo <[email protected]>
Unity-Result: CUE porcuepine <[email protected]>
Reviewed-by: Daniel Martí <[email protected]>
  • Loading branch information
rogpeppe committed Nov 13, 2023
1 parent 4e30101 commit b25fc05
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 0 deletions.
10 changes: 10 additions & 0 deletions cue/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ import (
// An error is returned if x is nil or not a pointer.
//
// If x is a struct, Decode will validate the constraints specified in the field tags.
//
// If x contains a [Value], that part of x will be set to the value
// at the corresponding part of v. This allows decoding values
// that aren't entirely concrete into a Go type.
func (v Value) Decode(x interface{}) error {
var d decoder
w := reflect.ValueOf(x)
Expand Down Expand Up @@ -71,6 +75,8 @@ func (d *decoder) clear(x reflect.Value) {
}
}

var valueType = reflect.TypeOf(Value{})

func (d *decoder) decode(x reflect.Value, v Value, isPtr bool) {
if !x.IsValid() {
d.addErr(errors.Newf(v.Pos(), "cannot decode into invalid value"))
Expand All @@ -87,6 +93,10 @@ func (d *decoder) decode(x reflect.Value, v Value, isPtr bool) {
d.addErr(err)
return
}
if x.Type() == valueType {
x.Set(reflect.ValueOf(v))
return
}

switch x.Kind() {
case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Interface:
Expand Down
21 changes: 21 additions & 0 deletions cue/decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
package cue

import (
"fmt"
"reflect"
"testing"
"time"

"github.com/go-quicktest/qt"
"github.com/google/go-cmp/cmp"
)

Expand Down Expand Up @@ -250,6 +252,25 @@ func TestDecode(t *testing.T) {
}
}

func TestDecodeIntoCUEValue(t *testing.T) {
// We should be able to decode into a CUE value so we can
// decode partially incomplete values into Go.
// This test doesn't fit within the table used by TestDecode
// because cue values aren't easily comparable with cmp.Diff.
var st struct {
X Value `json:"x"`
}
err := getInstance(t, `x: string`).Value().Decode(&st)
qt.Assert(t, qt.IsNil(err))
qt.Assert(t, qt.Equals(fmt.Sprint(st.X), "string"))

// Check we can decode into a top level value.
var v Value
err = getInstance(t, `int`).Value().Decode(&v)
qt.Assert(t, qt.IsNil(err))
qt.Assert(t, qt.Equals(fmt.Sprint(v), "int"))
}

type Duration struct {
D time.Duration
}
Expand Down

0 comments on commit b25fc05

Please sign in to comment.