cue: move Decode to separate file

This prepares for a complete rewrite.

Change-Id: I13126a97c5899d3492b296fc0bd9082d32f923f0
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9521
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/decode.go b/cue/decode.go
new file mode 100644
index 0000000..c27bd02
--- /dev/null
+++ b/cue/decode.go
@@ -0,0 +1,30 @@
+// Copyright 2021 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cue
+
+import (
+	"encoding/json"
+)
+
+// Decode initializes x with Value v. If x is a struct, it will validate the
+// constraints specified in the field tags.
+func (v Value) Decode(x interface{}) error {
+	// TODO: optimize
+	b, err := v.MarshalJSON()
+	if err != nil {
+		return err
+	}
+	return json.Unmarshal(b, x)
+}
diff --git a/cue/decode_test.go b/cue/decode_test.go
new file mode 100644
index 0000000..f3d43ea
--- /dev/null
+++ b/cue/decode_test.go
@@ -0,0 +1,96 @@
+// Copyright 2021 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cue
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+)
+
+func TestDecode(t *testing.T) {
+	type fields struct {
+		A int `json:"A"`
+		B int `json:"B"`
+		C int `json:"C"`
+	}
+	intList := func(ints ...int) *[]int {
+		ints = append([]int{}, ints...)
+		return &ints
+	}
+	testCases := []struct {
+		value string
+		dst   interface{}
+		want  interface{}
+		err   string
+	}{{
+		value: `_|_`,
+		err:   "explicit error (_|_ literal) in source",
+	}, {
+		value: `"str"`,
+		dst:   new(string),
+		want:  "str",
+	}, {
+		value: `"str"`,
+		dst:   new(int),
+		err:   "cannot unmarshal string into Go value of type int",
+	}, {
+		value: `{}`,
+		dst:   &fields{},
+		want:  fields{},
+	}, {
+		value: `{a:1,b:2,c:3}`,
+		dst:   &fields{},
+		want:  fields{A: 1, B: 2, C: 3},
+	}, {
+		value: `{for k, v in y if v > 1 {"\(k)": v} }
+		y: {a:1,b:2,c:3}`,
+		dst:  &fields{},
+		want: fields{B: 2, C: 3},
+	}, {
+		value: `{a:1,b:2,c:int}`,
+		dst:   new(fields),
+		err:   "cannot convert incomplete value",
+	}, {
+		value: `[]`,
+		dst:   intList(),
+		want:  *intList(),
+	}, {
+		value: `[1,2,3]`,
+		dst:   intList(),
+		want:  *intList(1, 2, 3),
+	}, {
+		value: `[for x in #y if x > 1 { x }]
+				#y: [1,2,3]`,
+		dst:  intList(),
+		want: *intList(2, 3),
+	}, {
+		value: `[int]`,
+		err:   "cannot convert incomplete value",
+	}}
+	for _, tc := range testCases {
+		t.Run(tc.value, func(t *testing.T) {
+			err := getInstance(t, tc.value).Value().Decode(tc.dst)
+			checkFatal(t, err, tc.err, "init")
+
+			got := reflect.ValueOf(tc.dst).Elem().Interface()
+			if !cmp.Equal(got, tc.want) {
+				t.Error(cmp.Diff(got, tc.want))
+				t.Errorf("\n%#v\n%#v", got, tc.want)
+			}
+		})
+	}
+}
diff --git a/cue/types.go b/cue/types.go
index 009a179..f2b2b09 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -1016,22 +1016,6 @@
 	}
 }
 
-// Decode initializes x with Value v. If x is a struct, it will validate the
-// constraints specified in the field tags.
-func (v Value) Decode(x interface{}) error {
-	// TODO: optimize
-	b, err := v.MarshalJSON()
-	if err != nil {
-		return err
-	}
-	return json.Unmarshal(b, x)
-}
-
-// // EncodeJSON generates JSON for the given value.
-// func (v Value) EncodeJSON(w io.Writer, v Value) error {
-// 	return nil
-// }
-
 // Doc returns all documentation comments associated with the field from which
 // the current value originates.
 func (v Value) Doc() []*ast.CommentGroup {
diff --git a/cue/types_test.go b/cue/types_test.go
index d5d613a..1768baa 100644
--- a/cue/types_test.go
+++ b/cue/types_test.go
@@ -1976,80 +1976,6 @@
 	}
 }
 
-func TestDecode(t *testing.T) {
-	type fields struct {
-		A int `json:"A"`
-		B int `json:"B"`
-		C int `json:"C"`
-	}
-	intList := func(ints ...int) *[]int {
-		ints = append([]int{}, ints...)
-		return &ints
-	}
-	testCases := []struct {
-		value string
-		dst   interface{}
-		want  interface{}
-		err   string
-	}{{
-		value: `_|_`,
-		err:   "explicit error (_|_ literal) in source",
-	}, {
-		value: `"str"`,
-		dst:   new(string),
-		want:  "str",
-	}, {
-		value: `"str"`,
-		dst:   new(int),
-		err:   "cannot unmarshal string into Go value of type int",
-	}, {
-		value: `{}`,
-		dst:   &fields{},
-		want:  fields{},
-	}, {
-		value: `{a:1,b:2,c:3}`,
-		dst:   &fields{},
-		want:  fields{A: 1, B: 2, C: 3},
-	}, {
-		value: `{for k, v in y if v > 1 {"\(k)": v} }
-		y: {a:1,b:2,c:3}`,
-		dst:  &fields{},
-		want: fields{B: 2, C: 3},
-	}, {
-		value: `{a:1,b:2,c:int}`,
-		dst:   new(fields),
-		err:   "cannot convert incomplete value",
-	}, {
-		value: `[]`,
-		dst:   intList(),
-		want:  *intList(),
-	}, {
-		value: `[1,2,3]`,
-		dst:   intList(),
-		want:  *intList(1, 2, 3),
-	}, {
-		value: `[for x in #y if x > 1 { x }]
-				#y: [1,2,3]`,
-		dst:  intList(),
-		want: *intList(2, 3),
-	}, {
-		value: `[int]`,
-		err:   "cannot convert incomplete value",
-	}}
-	for _, tc := range testCases {
-		t.Run(tc.value, func(t *testing.T) {
-			err := getInstance(t, tc.value).Value().Decode(tc.dst)
-			checkFatal(t, err, tc.err, "init")
-
-			got := reflect.ValueOf(tc.dst).Elem().Interface()
-			if !cmp.Equal(got, tc.want) {
-				t.Error(cmp.Diff(got, tc.want))
-				t.Errorf("\n%#v\n%#v", got, tc.want)
-			}
-		})
-	}
-}
-
 // TODO: options: disallow cycles.
 func TestValidate(t *testing.T) {
 	testCases := []struct {