1// Code generated by erb. DO NOT EDIT.
2
3package pgtype
4
5import (
6	"database/sql/driver"
7	"encoding/binary"
8	"fmt"
9	"reflect"
10
11	"github.com/jackc/pgio"
12)
13
14type TstzrangeArray struct {
15	Elements   []Tstzrange
16	Dimensions []ArrayDimension
17	Status     Status
18}
19
20func (dst *TstzrangeArray) Set(src interface{}) error {
21	// untyped nil and typed nil interfaces are different
22	if src == nil {
23		*dst = TstzrangeArray{Status: Null}
24		return nil
25	}
26
27	if value, ok := src.(interface{ Get() interface{} }); ok {
28		value2 := value.Get()
29		if value2 != value {
30			return dst.Set(value2)
31		}
32	}
33
34	// Attempt to match to select common types:
35	switch value := src.(type) {
36
37	case []Tstzrange:
38		if value == nil {
39			*dst = TstzrangeArray{Status: Null}
40		} else if len(value) == 0 {
41			*dst = TstzrangeArray{Status: Present}
42		} else {
43			*dst = TstzrangeArray{
44				Elements:   value,
45				Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
46				Status:     Present,
47			}
48		}
49	default:
50		// Fallback to reflection if an optimised match was not found.
51		// The reflection is necessary for arrays and multidimensional slices,
52		// but it comes with a 20-50% performance penalty for large arrays/slices
53		reflectedValue := reflect.ValueOf(src)
54		if !reflectedValue.IsValid() || reflectedValue.IsZero() {
55			*dst = TstzrangeArray{Status: Null}
56			return nil
57		}
58
59		dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
60		if !ok {
61			return fmt.Errorf("cannot find dimensions of %v for TstzrangeArray", src)
62		}
63		if elementsLength == 0 {
64			*dst = TstzrangeArray{Status: Present}
65			return nil
66		}
67		if len(dimensions) == 0 {
68			if originalSrc, ok := underlyingSliceType(src); ok {
69				return dst.Set(originalSrc)
70			}
71			return fmt.Errorf("cannot convert %v to TstzrangeArray", src)
72		}
73
74		*dst = TstzrangeArray{
75			Elements:   make([]Tstzrange, elementsLength),
76			Dimensions: dimensions,
77			Status:     Present,
78		}
79		elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
80		if err != nil {
81			// Maybe the target was one dimension too far, try again:
82			if len(dst.Dimensions) > 1 {
83				dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
84				elementsLength = 0
85				for _, dim := range dst.Dimensions {
86					if elementsLength == 0 {
87						elementsLength = int(dim.Length)
88					} else {
89						elementsLength *= int(dim.Length)
90					}
91				}
92				dst.Elements = make([]Tstzrange, elementsLength)
93				elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
94				if err != nil {
95					return err
96				}
97			} else {
98				return err
99			}
100		}
101		if elementCount != len(dst.Elements) {
102			return fmt.Errorf("cannot convert %v to TstzrangeArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
103		}
104	}
105
106	return nil
107}
108
109func (dst *TstzrangeArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
110	switch value.Kind() {
111	case reflect.Array:
112		fallthrough
113	case reflect.Slice:
114		if len(dst.Dimensions) == dimension {
115			break
116		}
117
118		valueLen := value.Len()
119		if int32(valueLen) != dst.Dimensions[dimension].Length {
120			return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
121		}
122		for i := 0; i < valueLen; i++ {
123			var err error
124			index, err = dst.setRecursive(value.Index(i), index, dimension+1)
125			if err != nil {
126				return 0, err
127			}
128		}
129
130		return index, nil
131	}
132	if !value.CanInterface() {
133		return 0, fmt.Errorf("cannot convert all values to TstzrangeArray")
134	}
135	if err := dst.Elements[index].Set(value.Interface()); err != nil {
136		return 0, fmt.Errorf("%v in TstzrangeArray", err)
137	}
138	index++
139
140	return index, nil
141}
142
143func (dst TstzrangeArray) Get() interface{} {
144	switch dst.Status {
145	case Present:
146		return dst
147	case Null:
148		return nil
149	default:
150		return dst.Status
151	}
152}
153
154func (src *TstzrangeArray) AssignTo(dst interface{}) error {
155	switch src.Status {
156	case Present:
157		if len(src.Dimensions) <= 1 {
158			// Attempt to match to select common types:
159			switch v := dst.(type) {
160
161			case *[]Tstzrange:
162				*v = make([]Tstzrange, len(src.Elements))
163				for i := range src.Elements {
164					if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
165						return err
166					}
167				}
168				return nil
169
170			}
171		}
172
173		// Try to convert to something AssignTo can use directly.
174		if nextDst, retry := GetAssignToDstType(dst); retry {
175			return src.AssignTo(nextDst)
176		}
177
178		// Fallback to reflection if an optimised match was not found.
179		// The reflection is necessary for arrays and multidimensional slices,
180		// but it comes with a 20-50% performance penalty for large arrays/slices
181		value := reflect.ValueOf(dst)
182		if value.Kind() == reflect.Ptr {
183			value = value.Elem()
184		}
185
186		switch value.Kind() {
187		case reflect.Array, reflect.Slice:
188		default:
189			return fmt.Errorf("cannot assign %T to %T", src, dst)
190		}
191
192		if len(src.Elements) == 0 {
193			if value.Kind() == reflect.Slice {
194				value.Set(reflect.MakeSlice(value.Type(), 0, 0))
195				return nil
196			}
197		}
198
199		elementCount, err := src.assignToRecursive(value, 0, 0)
200		if err != nil {
201			return err
202		}
203		if elementCount != len(src.Elements) {
204			return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
205		}
206
207		return nil
208	case Null:
209		return NullAssignTo(dst)
210	}
211
212	return fmt.Errorf("cannot decode %#v into %T", src, dst)
213}
214
215func (src *TstzrangeArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
216	switch kind := value.Kind(); kind {
217	case reflect.Array:
218		fallthrough
219	case reflect.Slice:
220		if len(src.Dimensions) == dimension {
221			break
222		}
223
224		length := int(src.Dimensions[dimension].Length)
225		if reflect.Array == kind {
226			typ := value.Type()
227			if typ.Len() != length {
228				return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
229			}
230			value.Set(reflect.New(typ).Elem())
231		} else {
232			value.Set(reflect.MakeSlice(value.Type(), length, length))
233		}
234
235		var err error
236		for i := 0; i < length; i++ {
237			index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
238			if err != nil {
239				return 0, err
240			}
241		}
242
243		return index, nil
244	}
245	if len(src.Dimensions) != dimension {
246		return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
247	}
248	if !value.CanAddr() {
249		return 0, fmt.Errorf("cannot assign all values from TstzrangeArray")
250	}
251	addr := value.Addr()
252	if !addr.CanInterface() {
253		return 0, fmt.Errorf("cannot assign all values from TstzrangeArray")
254	}
255	if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
256		return 0, err
257	}
258	index++
259	return index, nil
260}
261
262func (dst *TstzrangeArray) DecodeText(ci *ConnInfo, src []byte) error {
263	if src == nil {
264		*dst = TstzrangeArray{Status: Null}
265		return nil
266	}
267
268	uta, err := ParseUntypedTextArray(string(src))
269	if err != nil {
270		return err
271	}
272
273	var elements []Tstzrange
274
275	if len(uta.Elements) > 0 {
276		elements = make([]Tstzrange, len(uta.Elements))
277
278		for i, s := range uta.Elements {
279			var elem Tstzrange
280			var elemSrc []byte
281			if s != "NULL" || uta.Quoted[i] {
282				elemSrc = []byte(s)
283			}
284			err = elem.DecodeText(ci, elemSrc)
285			if err != nil {
286				return err
287			}
288
289			elements[i] = elem
290		}
291	}
292
293	*dst = TstzrangeArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
294
295	return nil
296}
297
298func (dst *TstzrangeArray) DecodeBinary(ci *ConnInfo, src []byte) error {
299	if src == nil {
300		*dst = TstzrangeArray{Status: Null}
301		return nil
302	}
303
304	var arrayHeader ArrayHeader
305	rp, err := arrayHeader.DecodeBinary(ci, src)
306	if err != nil {
307		return err
308	}
309
310	if len(arrayHeader.Dimensions) == 0 {
311		*dst = TstzrangeArray{Dimensions: arrayHeader.Dimensions, Status: Present}
312		return nil
313	}
314
315	elementCount := arrayHeader.Dimensions[0].Length
316	for _, d := range arrayHeader.Dimensions[1:] {
317		elementCount *= d.Length
318	}
319
320	elements := make([]Tstzrange, elementCount)
321
322	for i := range elements {
323		elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
324		rp += 4
325		var elemSrc []byte
326		if elemLen >= 0 {
327			elemSrc = src[rp : rp+elemLen]
328			rp += elemLen
329		}
330		err = elements[i].DecodeBinary(ci, elemSrc)
331		if err != nil {
332			return err
333		}
334	}
335
336	*dst = TstzrangeArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
337	return nil
338}
339
340func (src TstzrangeArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
341	switch src.Status {
342	case Null:
343		return nil, nil
344	case Undefined:
345		return nil, errUndefined
346	}
347
348	if len(src.Dimensions) == 0 {
349		return append(buf, '{', '}'), nil
350	}
351
352	buf = EncodeTextArrayDimensions(buf, src.Dimensions)
353
354	// dimElemCounts is the multiples of elements that each array lies on. For
355	// example, a single dimension array of length 4 would have a dimElemCounts of
356	// [4]. A multi-dimensional array of lengths [3,5,2] would have a
357	// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
358	// or '}'.
359	dimElemCounts := make([]int, len(src.Dimensions))
360	dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
361	for i := len(src.Dimensions) - 2; i > -1; i-- {
362		dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
363	}
364
365	inElemBuf := make([]byte, 0, 32)
366	for i, elem := range src.Elements {
367		if i > 0 {
368			buf = append(buf, ',')
369		}
370
371		for _, dec := range dimElemCounts {
372			if i%dec == 0 {
373				buf = append(buf, '{')
374			}
375		}
376
377		elemBuf, err := elem.EncodeText(ci, inElemBuf)
378		if err != nil {
379			return nil, err
380		}
381		if elemBuf == nil {
382			buf = append(buf, `NULL`...)
383		} else {
384			buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
385		}
386
387		for _, dec := range dimElemCounts {
388			if (i+1)%dec == 0 {
389				buf = append(buf, '}')
390			}
391		}
392	}
393
394	return buf, nil
395}
396
397func (src TstzrangeArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
398	switch src.Status {
399	case Null:
400		return nil, nil
401	case Undefined:
402		return nil, errUndefined
403	}
404
405	arrayHeader := ArrayHeader{
406		Dimensions: src.Dimensions,
407	}
408
409	if dt, ok := ci.DataTypeForName("tstzrange"); ok {
410		arrayHeader.ElementOID = int32(dt.OID)
411	} else {
412		return nil, fmt.Errorf("unable to find oid for type name %v", "tstzrange")
413	}
414
415	for i := range src.Elements {
416		if src.Elements[i].Status == Null {
417			arrayHeader.ContainsNull = true
418			break
419		}
420	}
421
422	buf = arrayHeader.EncodeBinary(ci, buf)
423
424	for i := range src.Elements {
425		sp := len(buf)
426		buf = pgio.AppendInt32(buf, -1)
427
428		elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
429		if err != nil {
430			return nil, err
431		}
432		if elemBuf != nil {
433			buf = elemBuf
434			pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
435		}
436	}
437
438	return buf, nil
439}
440
441// Scan implements the database/sql Scanner interface.
442func (dst *TstzrangeArray) Scan(src interface{}) error {
443	if src == nil {
444		return dst.DecodeText(nil, nil)
445	}
446
447	switch src := src.(type) {
448	case string:
449		return dst.DecodeText(nil, []byte(src))
450	case []byte:
451		srcCopy := make([]byte, len(src))
452		copy(srcCopy, src)
453		return dst.DecodeText(nil, srcCopy)
454	}
455
456	return fmt.Errorf("cannot scan %T", src)
457}
458
459// Value implements the database/sql/driver Valuer interface.
460func (src TstzrangeArray) Value() (driver.Value, error) {
461	buf, err := src.EncodeText(nil, nil)
462	if err != nil {
463		return nil, err
464	}
465	if buf == nil {
466		return nil, nil
467	}
468
469	return string(buf), nil
470}
471