@@ -24,6 +24,7 @@ import com.amazon.ion.SpanProvider
2424import com.amazon.ion.TextSpan
2525import com.amazon.ion.system.IonReaderBuilder
2626import com.amazon.ionelement.api.*
27+ import kotlinx.collections.immutable.toPersistentMap
2728
2829internal class IonElementLoaderImpl (private val options : IonElementLoaderOptions ) : IonElementLoader {
2930
@@ -59,9 +60,7 @@ internal class IonElementLoaderImpl(private val options: IonElementLoaderOptions
5960 }
6061
6162 override fun loadSingleElement (ionText : String ): AnyElement =
62- IonReaderBuilder .standard().build(ionText).use { ionReader ->
63- loadSingleElement(ionReader)
64- }
63+ IonReaderBuilder .standard().build(ionText).use(::loadSingleElement)
6564
6665 override fun loadSingleElement (ionReader : IonReader ): AnyElement {
6766 return handleReaderException(ionReader) {
@@ -75,28 +74,22 @@ internal class IonElementLoaderImpl(private val options: IonElementLoaderOptions
7574
7675 override fun loadAllElements (ionReader : IonReader ): List <AnyElement > {
7776 return handleReaderException(ionReader) {
78- mutableListOf<AnyElement >().also { fields ->
79- ionReader.forEachValue { fields.add(loadCurrentElement(ionReader)) }
77+ val elements = mutableListOf<AnyElement >()
78+ while (ionReader.next() != null ) {
79+ elements.add(loadCurrentElement(ionReader))
8080 }
81+ elements
8182 }
8283 }
8384
8485 override fun loadAllElements (ionText : String ): List <AnyElement > =
85- IonReaderBuilder .standard().build(ionText).use { ionReader ->
86- return ArrayList <AnyElement >().also { list ->
87- ionReader.forEachValue {
88- list.add(loadCurrentElement(ionReader))
89- }
90- }.toList()
91- }
86+ IonReaderBuilder .standard().build(ionText).use(::loadAllElements)
9287
9388 override fun loadCurrentElement (ionReader : IonReader ): AnyElement {
9489 return handleReaderException(ionReader) {
95- require (ionReader.type != null ) { " The IonReader was not positioned at an element." }
90+ val valueType = requireNotNull (ionReader.type) { " The IonReader was not positioned at an element." }
9691
97- val valueType = ionReader.type
98-
99- val annotations = ionReader.typeAnnotations!!
92+ val annotations = ionReader.typeAnnotations!! .asList().toEmptyOrPersistentList()
10093
10194 val metas = when {
10295 options.includeLocationMeta -> {
@@ -107,83 +100,67 @@ internal class IonElementLoaderImpl(private val options: IonElementLoaderOptions
107100 }
108101 }
109102 else -> emptyMetaContainer()
110- }
111-
112- var element: AnyElement = when {
113- ionReader.type == IonType .DATAGRAM -> error(" IonElementLoaderImpl does not know what to do with IonType.DATAGRAM" )
114- ionReader.isNullValue -> ionNull(valueType.toElementType())
115- else -> {
116- when {
117- ! IonType .isContainer(valueType) -> {
118- when (valueType) {
119- IonType .BOOL -> ionBool(ionReader.booleanValue())
120- IonType .INT -> when (ionReader.integerSize!! ) {
121- IntegerSize .BIG_INTEGER -> {
122- val bigIntValue = ionReader.bigIntegerValue()
123- // Ion java's IonReader appears to determine integerSize based on number of bits,
124- // not on the actual value, which means if we have a padded int that is > 63 bits,
125- // but whose value only uses <= 63 bits then integerSize is still BIG_INTEGER.
126- // Compensate for that here...
127- if (bigIntValue !in RANGE_OF_LONG )
128- ionInt(bigIntValue)
129- else {
130- ionInt(ionReader.longValue())
131- }
132- }
133- IntegerSize .LONG , IntegerSize .INT -> ionInt(ionReader.longValue())
134- }
135- IonType .FLOAT -> ionFloat(ionReader.doubleValue())
136- IonType .DECIMAL -> ionDecimal(ionReader.decimalValue())
137- IonType .TIMESTAMP -> ionTimestamp(ionReader.timestampValue())
138- IonType .STRING -> ionString(ionReader.stringValue())
139- IonType .SYMBOL -> ionSymbol(ionReader.stringValue())
140- IonType .CLOB -> ionClob(ionReader.newBytes())
141- IonType .BLOB -> ionBlob(ionReader.newBytes())
142- else ->
143- error(" Unexpected Ion type for scalar Ion data type ${ionReader.type} ." )
103+ }.toPersistentMap()
104+
105+ if (ionReader.isNullValue) {
106+ ionNull(valueType.toElementType(), annotations, metas)
107+ } else {
108+ when (valueType) {
109+ IonType .BOOL -> BoolElementImpl (ionReader.booleanValue(), annotations, metas)
110+ IonType .INT -> when (ionReader.integerSize!! ) {
111+ IntegerSize .BIG_INTEGER -> {
112+ val bigIntValue = ionReader.bigIntegerValue()
113+ // Ion java's IonReader appears to determine integerSize based on number of bits,
114+ // not on the actual value, which means if we have a padded int that is > 63 bits,
115+ // but whose value only uses <= 63 bits then integerSize is still BIG_INTEGER.
116+ // Compensate for that here...
117+ if (bigIntValue !in RANGE_OF_LONG )
118+ BigIntIntElementImpl (bigIntValue, annotations, metas)
119+ else {
120+ LongIntElementImpl (ionReader.longValue(), annotations, metas)
144121 }
145122 }
146- else -> {
147- ionReader.stepIn()
148- when (valueType) {
149- IonType .LIST -> {
150- ionListOf(loadAllElements(ionReader))
151- }
152- IonType .SEXP -> {
153- ionSexpOf(loadAllElements(ionReader))
154- }
155- IonType .STRUCT -> {
156- val fields = mutableListOf<StructField >()
157- ionReader.forEachValue { fields.add(StructFieldImpl (ionReader.fieldName, loadCurrentElement(ionReader))) }
158- ionStructOf(fields)
159- }
160- else -> error(" Unexpected Ion type for container Ion data type ${ionReader.type} ." )
161- }.also {
162- ionReader.stepOut()
163- }
123+ IntegerSize .LONG ,
124+ IntegerSize .INT -> LongIntElementImpl (ionReader.longValue(), annotations, metas)
125+ }
126+
127+ IonType .FLOAT -> FloatElementImpl (ionReader.doubleValue(), annotations, metas)
128+ IonType .DECIMAL -> DecimalElementImpl (ionReader.decimalValue(), annotations, metas)
129+ IonType .TIMESTAMP -> TimestampElementImpl (ionReader.timestampValue(), annotations, metas)
130+ IonType .STRING -> StringElementImpl (ionReader.stringValue(), annotations, metas)
131+ IonType .SYMBOL -> SymbolElementImpl (ionReader.stringValue(), annotations, metas)
132+ IonType .CLOB -> ClobElementImpl (ionReader.newBytes(), annotations, metas)
133+ IonType .BLOB -> BlobElementImpl (ionReader.newBytes(), annotations, metas)
134+ IonType .LIST -> {
135+ ionReader.stepIn()
136+ val list = ListElementImpl (loadAllElements(ionReader).toEmptyOrPersistentList(), annotations, metas)
137+ ionReader.stepOut()
138+ list
139+ }
140+ IonType .SEXP -> {
141+ ionReader.stepIn()
142+ val sexp = SexpElementImpl (loadAllElements(ionReader).toEmptyOrPersistentList(), annotations, metas)
143+ ionReader.stepOut()
144+ sexp
145+ }
146+ IonType .STRUCT -> {
147+ val fields = mutableListOf<StructField >()
148+ ionReader.stepIn()
149+ while (ionReader.next() != null ) {
150+ fields.add(
151+ StructFieldImpl (
152+ ionReader.fieldName,
153+ loadCurrentElement(ionReader)
154+ )
155+ )
164156 }
157+ ionReader.stepOut()
158+ StructElementImpl (fields.toEmptyOrPersistentList(), annotations, metas)
165159 }
160+ IonType .DATAGRAM -> error(" IonElementLoaderImpl does not know what to do with IonType.DATAGRAM" )
161+ IonType .NULL -> error(" IonType.NULL branch should be unreachable" )
166162 }
167163 }.asAnyElement()
168-
169- if (annotations.any()) {
170- element = element._withAnnotations (* annotations)
171- }
172- if (metas.any()) {
173- element = element._withMetas (metas)
174- }
175-
176- element
177164 }
178165 }
179166}
180-
181- /* *
182- * Calls [IonReader.next] and invokes [block] until all values at the current level in the [IonReader]
183- * have been exhausted.
184- * */
185- private fun <T > IonReader.forEachValue (block : () -> T ) {
186- while (this .next() != null ) {
187- block()
188- }
189- }
0 commit comments