1package jsoniter
2
3import (
4	"fmt"
5	"github.com/modern-go/reflect2"
6	"io"
7	"unsafe"
8)
9
10func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder {
11	sliceType := typ.(*reflect2.UnsafeSliceType)
12	decoder := decoderOfType(ctx.append("[sliceElem]"), sliceType.Elem())
13	return &sliceDecoder{sliceType, decoder}
14}
15
16func encoderOfSlice(ctx *ctx, typ reflect2.Type) ValEncoder {
17	sliceType := typ.(*reflect2.UnsafeSliceType)
18	encoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem())
19	return &sliceEncoder{sliceType, encoder}
20}
21
22type sliceEncoder struct {
23	sliceType   *reflect2.UnsafeSliceType
24	elemEncoder ValEncoder
25}
26
27func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
28	if encoder.sliceType.UnsafeIsNil(ptr) {
29		stream.WriteNil()
30		return
31	}
32	length := encoder.sliceType.UnsafeLengthOf(ptr)
33	if length == 0 {
34		stream.WriteEmptyArray()
35		return
36	}
37	stream.WriteArrayStart()
38	encoder.elemEncoder.Encode(encoder.sliceType.UnsafeGetIndex(ptr, 0), stream)
39	for i := 1; i < length; i++ {
40		stream.WriteMore()
41		elemPtr := encoder.sliceType.UnsafeGetIndex(ptr, i)
42		encoder.elemEncoder.Encode(elemPtr, stream)
43	}
44	stream.WriteArrayEnd()
45	if stream.Error != nil && stream.Error != io.EOF {
46		stream.Error = fmt.Errorf("%v: %s", encoder.sliceType, stream.Error.Error())
47	}
48}
49
50func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool {
51	return encoder.sliceType.UnsafeLengthOf(ptr) == 0
52}
53
54type sliceDecoder struct {
55	sliceType   *reflect2.UnsafeSliceType
56	elemDecoder ValDecoder
57}
58
59func (decoder *sliceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
60	decoder.doDecode(ptr, iter)
61	if iter.Error != nil && iter.Error != io.EOF {
62		iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
63	}
64}
65
66func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
67	c := iter.nextToken()
68	sliceType := decoder.sliceType
69	if c == 'n' {
70		iter.skipThreeBytes('u', 'l', 'l')
71		sliceType.UnsafeSetNil(ptr)
72		return
73	}
74	if c != '[' {
75		iter.ReportError("decode slice", "expect [ or n, but found "+string([]byte{c}))
76		return
77	}
78	c = iter.nextToken()
79	if c == ']' {
80		sliceType.UnsafeSet(ptr, sliceType.UnsafeMakeSlice(0, 0))
81		return
82	}
83	iter.unreadByte()
84	sliceType.UnsafeGrow(ptr, 1)
85	elemPtr := sliceType.UnsafeGetIndex(ptr, 0)
86	decoder.elemDecoder.Decode(elemPtr, iter)
87	length := 1
88	for c = iter.nextToken(); c == ','; c = iter.nextToken() {
89		idx := length
90		length += 1
91		sliceType.UnsafeGrow(ptr, length)
92		elemPtr = sliceType.UnsafeGetIndex(ptr, idx)
93		decoder.elemDecoder.Decode(elemPtr, iter)
94	}
95	if c != ']' {
96		iter.ReportError("decode slice", "expect ], but found "+string([]byte{c}))
97		return
98	}
99}
100