aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/zclconf/go-cty/cty/gob.go
blob: 3d731993bc26f4e5c38f234ef0e7804e6e837457 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package cty

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"math/big"
)

// GobEncode is an implementation of the gob.GobEncoder interface, which
// allows Values to be included in structures encoded with encoding/gob.
//
// Currently it is not possible to represent values of capsule types in gob,
// because the types themselves cannot be represented.
func (val Value) GobEncode() ([]byte, error) {
	buf := &bytes.Buffer{}
	enc := gob.NewEncoder(buf)

	gv := gobValue{
		Version: 0,
		Ty:      val.ty,
		V:       val.v,
	}

	err := enc.Encode(gv)
	if err != nil {
		return nil, fmt.Errorf("error encoding cty.Value: %s", err)
	}

	return buf.Bytes(), nil
}

// GobDecode is an implementation of the gob.GobDecoder interface, which
// inverts the operation performed by GobEncode. See the documentation of
// GobEncode for considerations when using cty.Value instances with gob.
func (val *Value) GobDecode(buf []byte) error {
	r := bytes.NewReader(buf)
	dec := gob.NewDecoder(r)

	var gv gobValue
	err := dec.Decode(&gv)
	if err != nil {
		return fmt.Errorf("error decoding cty.Value: %s", err)
	}
	if gv.Version != 0 {
		return fmt.Errorf("unsupported cty.Value encoding version %d; only 0 is supported", gv.Version)
	}

	// big.Float seems to, for some reason, lose its "pointerness" when we
	// round-trip it, so we'll fix that here.
	if bf, ok := gv.V.(big.Float); ok {
		gv.V = &bf
	}

	val.ty = gv.Ty
	val.v = gv.V

	return nil
}

// GobEncode is an implementation of the gob.GobEncoder interface, which
// allows Types to be included in structures encoded with encoding/gob.
//
// Currently it is not possible to represent capsule types in gob.
func (t Type) GobEncode() ([]byte, error) {
	buf := &bytes.Buffer{}
	enc := gob.NewEncoder(buf)

	gt := gobType{
		Version: 0,
		Impl:    t.typeImpl,
	}

	err := enc.Encode(gt)
	if err != nil {
		return nil, fmt.Errorf("error encoding cty.Type: %s", err)
	}

	return buf.Bytes(), nil
}

// GobDecode is an implementatino of the gob.GobDecoder interface, which
// reverses the encoding performed by GobEncode to allow types to be recovered
// from gob buffers.
func (t *Type) GobDecode(buf []byte) error {
	r := bytes.NewReader(buf)
	dec := gob.NewDecoder(r)

	var gt gobType
	err := dec.Decode(&gt)
	if err != nil {
		return fmt.Errorf("error decoding cty.Type: %s", err)
	}
	if gt.Version != 0 {
		return fmt.Errorf("unsupported cty.Type encoding version %d; only 0 is supported", gt.Version)
	}

	t.typeImpl = gt.Impl

	return nil
}

// Capsule types cannot currently be gob-encoded, because they rely on pointer
// equality and we have no way to recover the original pointer on decode.
func (t *capsuleType) GobEncode() ([]byte, error) {
	return nil, fmt.Errorf("cannot gob-encode capsule type %q", t.FriendlyName())
}

func (t *capsuleType) GobDecode() ([]byte, error) {
	return nil, fmt.Errorf("cannot gob-decode capsule type %q", t.FriendlyName())
}

type gobValue struct {
	Version int
	Ty      Type
	V       interface{}
}

type gobType struct {
	Version int
	Impl    typeImpl
}

type gobCapsuleTypeImpl struct {
}