1/*
2Copyright 2014 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package runtime
18
19import (
20	"errors"
21
22	"k8s.io/apimachinery/pkg/conversion"
23	"k8s.io/apimachinery/pkg/runtime/schema"
24)
25
26type encodable struct {
27	E        Encoder `json:"-"`
28	obj      Object
29	versions []schema.GroupVersion
30}
31
32func (e encodable) GetObjectKind() schema.ObjectKind { return e.obj.GetObjectKind() }
33func (e encodable) DeepCopyObject() Object {
34	var out encodable = e
35	out.obj = e.obj.DeepCopyObject()
36	copy(out.versions, e.versions)
37	return out
38}
39
40// NewEncodable creates an object that will be encoded with the provided codec on demand.
41// Provided as a convenience for test cases dealing with internal objects.
42func NewEncodable(e Encoder, obj Object, versions ...schema.GroupVersion) Object {
43	if _, ok := obj.(*Unknown); ok {
44		return obj
45	}
46	return encodable{e, obj, versions}
47}
48
49func (re encodable) UnmarshalJSON(in []byte) error {
50	return errors.New("runtime.encodable cannot be unmarshalled from JSON")
51}
52
53// Marshal may get called on pointers or values, so implement MarshalJSON on value.
54// http://stackoverflow.com/questions/21390979/custom-marshaljson-never-gets-called-in-go
55func (re encodable) MarshalJSON() ([]byte, error) {
56	return Encode(re.E, re.obj)
57}
58
59// NewEncodableList creates an object that will be encoded with the provided codec on demand.
60// Provided as a convenience for test cases dealing with internal objects.
61func NewEncodableList(e Encoder, objects []Object, versions ...schema.GroupVersion) []Object {
62	out := make([]Object, len(objects))
63	for i := range objects {
64		if _, ok := objects[i].(*Unknown); ok {
65			out[i] = objects[i]
66			continue
67		}
68		out[i] = NewEncodable(e, objects[i], versions...)
69	}
70	return out
71}
72
73func (re *Unknown) UnmarshalJSON(in []byte) error {
74	if re == nil {
75		return errors.New("runtime.Unknown: UnmarshalJSON on nil pointer")
76	}
77	re.TypeMeta = TypeMeta{}
78	re.Raw = append(re.Raw[0:0], in...)
79	re.ContentEncoding = ""
80	re.ContentType = ContentTypeJSON
81	return nil
82}
83
84// Marshal may get called on pointers or values, so implement MarshalJSON on value.
85// http://stackoverflow.com/questions/21390979/custom-marshaljson-never-gets-called-in-go
86func (re Unknown) MarshalJSON() ([]byte, error) {
87	// If ContentType is unset, we assume this is JSON.
88	if re.ContentType != "" && re.ContentType != ContentTypeJSON {
89		return nil, errors.New("runtime.Unknown: MarshalJSON on non-json data")
90	}
91	if re.Raw == nil {
92		return []byte("null"), nil
93	}
94	return re.Raw, nil
95}
96
97func Convert_runtime_Object_To_runtime_RawExtension(in *Object, out *RawExtension, s conversion.Scope) error {
98	if in == nil {
99		out.Raw = []byte("null")
100		return nil
101	}
102	obj := *in
103	if unk, ok := obj.(*Unknown); ok {
104		if unk.Raw != nil {
105			out.Raw = unk.Raw
106			return nil
107		}
108		obj = out.Object
109	}
110	if obj == nil {
111		out.Raw = nil
112		return nil
113	}
114	out.Object = obj
115	return nil
116}
117
118func Convert_runtime_RawExtension_To_runtime_Object(in *RawExtension, out *Object, s conversion.Scope) error {
119	if in.Object != nil {
120		*out = in.Object
121		return nil
122	}
123	data := in.Raw
124	if len(data) == 0 || (len(data) == 4 && string(data) == "null") {
125		*out = nil
126		return nil
127	}
128	*out = &Unknown{
129		Raw: data,
130		// TODO: Set ContentEncoding and ContentType appropriately.
131		// Currently we set ContentTypeJSON to make tests passing.
132		ContentType: ContentTypeJSON,
133	}
134	return nil
135}
136
137func DefaultEmbeddedConversions() []interface{} {
138	return []interface{}{
139		Convert_runtime_Object_To_runtime_RawExtension,
140		Convert_runtime_RawExtension_To_runtime_Object,
141	}
142}
143