1
+ /*
2
+ * Copyright 2019-2021 JetBrains s.r.o.
3
+ * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
4
+ */
5
+
6
+ package kotlinx.datetime.serializers
7
+
8
+ import kotlinx.datetime.DatePeriod
9
+ import kotlinx.datetime.DateTimePeriod
10
+ import kotlinx.serialization.KSerializer
11
+ import kotlinx.serialization.SerializationException
12
+ import kotlinx.serialization.descriptors.*
13
+ import kotlinx.serialization.encoding.*
14
+
15
+ object DateTimePeriodComponentSerializer: KSerializer<DateTimePeriod> {
16
+
17
+ override val descriptor: SerialDescriptor =
18
+ buildClassSerialDescriptor(" DateTimePeriod" ) {
19
+ element<Int >(" years" , isOptional = true )
20
+ element<Int >(" months" , isOptional = true )
21
+ element<Int >(" days" , isOptional = true )
22
+ element<Int >(" hours" , isOptional = true )
23
+ element<Int >(" minutes" , isOptional = true )
24
+ element<Int >(" seconds" , isOptional = true )
25
+ element<Long >(" nanoseconds" , isOptional = true )
26
+ }
27
+
28
+ override fun deserialize (decoder : Decoder ): DateTimePeriod =
29
+ decoder.decodeStructure(descriptor) {
30
+ var years = 0
31
+ var months = 0
32
+ var days = 0
33
+ var hours = 0
34
+ var minutes = 0
35
+ var seconds = 0
36
+ var nanoseconds = 0L
37
+ loop@while (true ) {
38
+ when (val index = decodeElementIndex(descriptor)) {
39
+ 0 -> years = decodeIntElement(descriptor, 0 )
40
+ 1 -> months = decodeIntElement(descriptor, 1 )
41
+ 2 -> days = decodeIntElement(descriptor, 2 )
42
+ 3 -> hours = decodeIntElement(descriptor, 3 )
43
+ 4 -> minutes = decodeIntElement(descriptor, 4 )
44
+ 5 -> seconds = decodeIntElement(descriptor, 5 )
45
+ 6 -> nanoseconds = decodeLongElement(descriptor, 6 )
46
+ CompositeDecoder .DECODE_DONE -> break @loop // https://youtrack.jetbrains.com/issue/KT-42262
47
+ else -> throw SerializationException (" Unexpected index: $index " )
48
+ }
49
+ }
50
+ DateTimePeriod (years, months, days, hours, minutes, seconds, nanoseconds)
51
+ }
52
+
53
+ override fun serialize (encoder : Encoder , value : DateTimePeriod ) {
54
+ encoder.encodeStructure(descriptor) {
55
+ with (value) {
56
+ if (years != 0 ) encodeIntElement(descriptor, 0 , years)
57
+ if (months != 0 ) encodeIntElement(descriptor, 1 , months)
58
+ if (days != 0 ) encodeIntElement(descriptor, 2 , days)
59
+ if (hours != 0 ) encodeIntElement(descriptor, 3 , hours)
60
+ if (minutes != 0 ) encodeIntElement(descriptor, 4 , minutes)
61
+ if (seconds != 0 ) encodeIntElement(descriptor, 5 , seconds)
62
+ if (nanoseconds != 0 ) encodeLongElement(descriptor, 6 , value.nanoseconds.toLong())
63
+ }
64
+ }
65
+ }
66
+
67
+ }
68
+
69
+ object DateTimePeriodIso8601Serializer: KSerializer<DateTimePeriod> {
70
+
71
+ override val descriptor: SerialDescriptor =
72
+ PrimitiveSerialDescriptor (" DateTimePeriod" , PrimitiveKind .STRING )
73
+
74
+ override fun deserialize (decoder : Decoder ): DateTimePeriod =
75
+ DateTimePeriod .parse(decoder.decodeString())
76
+
77
+ override fun serialize (encoder : Encoder , value : DateTimePeriod ) {
78
+ encoder.encodeString(value.toString())
79
+ }
80
+
81
+ }
82
+
83
+ object DatePeriodComponentSerializer: KSerializer<DatePeriod> {
84
+
85
+ private fun unexpectedNonzero (fieldName : String , value : Long ) {
86
+ if (value != 0L ) {
87
+ throw SerializationException (" DatePeriod should have non-date components be zero, but got $value in '$fieldName '" )
88
+ }
89
+ }
90
+
91
+ private fun unexpectedNonzero (fieldName : String , value : Int ) = unexpectedNonzero(fieldName, value.toLong())
92
+
93
+ override val descriptor: SerialDescriptor =
94
+ buildClassSerialDescriptor(" DatePeriod" ) {
95
+ element<Int >(" years" , isOptional = true )
96
+ element<Int >(" months" , isOptional = true )
97
+ element<Int >(" days" , isOptional = true )
98
+ element<Int >(" hours" , isOptional = true )
99
+ element<Int >(" minutes" , isOptional = true )
100
+ element<Int >(" seconds" , isOptional = true )
101
+ element<Long >(" nanoseconds" , isOptional = true )
102
+ }
103
+
104
+ override fun deserialize (decoder : Decoder ): DatePeriod =
105
+ decoder.decodeStructure(descriptor) {
106
+ var years = 0
107
+ var months = 0
108
+ var days = 0
109
+ loop@while (true ) {
110
+ when (val index = decodeElementIndex(descriptor)) {
111
+ 0 -> years = decodeIntElement(descriptor, 0 )
112
+ 1 -> months = decodeIntElement(descriptor, 1 )
113
+ 2 -> days = decodeIntElement(descriptor, 2 )
114
+ 3 -> unexpectedNonzero(" hours" , decodeIntElement(descriptor, 3 ))
115
+ 4 -> unexpectedNonzero(" minutes" , decodeIntElement(descriptor, 4 ))
116
+ 5 -> unexpectedNonzero(" seconds" , decodeIntElement(descriptor, 5 ))
117
+ 6 -> unexpectedNonzero(" nanoseconds" , decodeLongElement(descriptor, 6 ))
118
+ CompositeDecoder .DECODE_DONE -> break @loop // https://youtrack.jetbrains.com/issue/KT-42262
119
+ else -> throw SerializationException (" Unexpected index: $index " )
120
+ }
121
+ }
122
+ DatePeriod (years, months, days)
123
+ }
124
+
125
+ override fun serialize (encoder : Encoder , value : DatePeriod ) {
126
+ encoder.encodeStructure(descriptor) {
127
+ with (value) {
128
+ if (years != 0 ) encodeIntElement(DateTimePeriodComponentSerializer .descriptor, 0 , years)
129
+ if (months != 0 ) encodeIntElement(DateTimePeriodComponentSerializer .descriptor, 1 , months)
130
+ if (days != 0 ) encodeIntElement(DateTimePeriodComponentSerializer .descriptor, 2 , days)
131
+ }
132
+ }
133
+ }
134
+
135
+ }
136
+
137
+ object DatePeriodIso8601Serializer: KSerializer<DatePeriod> {
138
+
139
+ override val descriptor: SerialDescriptor =
140
+ PrimitiveSerialDescriptor (" DatePeriod" , PrimitiveKind .STRING )
141
+
142
+ // TODO: consider whether should fail when parsing "P1YT0H0M0.0S"
143
+ override fun deserialize (decoder : Decoder ): DatePeriod =
144
+ when (val period = DateTimePeriod .parse(decoder.decodeString())) {
145
+ is DatePeriod -> period
146
+ else -> throw SerializationException (" $period is not a date-based period" )
147
+ }
148
+
149
+ override fun serialize (encoder : Encoder , value : DatePeriod ) {
150
+ encoder.encodeString(value.toString())
151
+ }
152
+
153
+ }
0 commit comments