001package Torello.JSON;
002
003import Torello.Java.StringParse;
004import Torello.Java.UnreachableError;
005
006import Torello.Java.Additional.Counter;
007
008import java.lang.reflect.Array;
009
010import java.util.function.Function;
011import java.util.function.ObjIntConsumer;
012
013import java.util.stream.Stream;
014import java.util.stream.IntStream;
015import java.util.stream.LongStream;
016import java.util.stream.DoubleStream;
017
018import javax.json.JsonArray;
019import javax.json.JsonValue;
020
021import static javax.json.JsonValue.ValueType.*;
022
023@Torello.JavaDoc.Annotations.StaticFunctional
024public class GENERATE_1DARRAY
025{
026    private GENERATE_1DARRAY() { }
027
028
029    // @SuppressWarnings({"unchecked", "rawtypes"})
030    @SuppressWarnings("unchecked")
031    static <T> Function<JsonArray, Object> retrieveAppropriateGenerator(
032            final SettingsRec<?, ?> rec,
033            final BASIC_TYPES<T>    bt,
034            final boolean           boxedOrPrimitive
035        )
036    {
037        switch (bt.whichType)
038        {
039            case BASIC_TYPES.INTEGER: return boxedOrPrimitive 
040
041                ? (JsonArray ja) -> ProcessJsonArray
042                    .numericToJava(ja, (SettingsRec<Integer, Stream<Integer>>) rec)
043                    .toArray(Integer[]::new)
044
045                : (JsonArray ja) -> ProcessJsonArray
046                    .numericToJava(ja, (SettingsRec<Integer, IntStream>) rec)
047                    .toArray();
048
049
050            case BASIC_TYPES.SHORT: return boxedOrPrimitive
051
052                ? (JsonArray ja) -> ProcessJsonArray
053                    .numericToJava(ja, (SettingsRec<Short, Stream<Short>>) rec)
054                    .toArray(Short[]::new)
055
056                : (JsonArray ja) ->
057                    array1DGeneratorShort(ja, (SettingsRec<Short, Stream<Short>>) rec);
058
059
060            case BASIC_TYPES.BYTE: return boxedOrPrimitive
061
062                ? (JsonArray ja) -> ProcessJsonArray
063                    .numericToJava(ja, (SettingsRec<Byte, Stream<Byte>>) rec)
064                    .toArray(Byte[]::new)
065
066                : (JsonArray ja) ->
067                    array1DGeneratorByte(ja, (SettingsRec<Byte, Stream<Byte>>) rec);
068
069
070            case BASIC_TYPES.LONG: return boxedOrPrimitive
071
072                ? (JsonArray ja) -> ProcessJsonArray
073                    .numericToJava(ja, (SettingsRec<Long, Stream<Long>>) rec)
074                    .toArray(Long[]::new)
075
076                : (JsonArray ja) -> ProcessJsonArray
077                    .numericToJava(ja, (SettingsRec<Long, LongStream>) rec)
078                    .toArray();
079
080
081            case BASIC_TYPES.DOUBLE: return boxedOrPrimitive
082
083                ? (JsonArray ja) -> ProcessJsonArray
084                    .numericToJava(ja, (SettingsRec<Double, Stream<Double>>) rec)
085                    .toArray(Double[]::new)
086
087                : (JsonArray ja) -> ProcessJsonArray
088                    .numericToJava(ja, (SettingsRec<Double, DoubleStream>) rec)
089                    .toArray();
090
091
092            case BASIC_TYPES.FLOAT: return boxedOrPrimitive
093
094                ? (JsonArray ja) -> ProcessJsonArray
095                    .numericToJava(ja, (SettingsRec<Float, Stream<Float>>) rec)
096                    .toArray(Float[]::new)
097
098                : (JsonArray ja) ->
099                    array1DGeneratorFloat(ja, (SettingsRec<Float, Stream<Float>>) rec);
100
101
102            case BASIC_TYPES.BOOLEAN: return boxedOrPrimitive
103
104                ? (JsonArray ja) -> ProcessJsonArray
105                    .booleanToJava(ja, (SettingsRec<Boolean, Stream<Boolean>>) rec)
106                    .toArray(Boolean[]::new)
107
108                : (JsonArray ja) ->
109                    array1DGeneratorBoolean(ja, (SettingsRec<Boolean, Stream<Boolean>>) rec);
110
111
112            case BASIC_TYPES.NUMBER:
113
114                return (JsonArray ja) -> ProcessJsonArray
115                    .numericToJava(ja, (SettingsRec<Number, Stream<Number>>) rec)
116                    .toArray(Number[]::new);
117
118
119            case BASIC_TYPES.STRING:
120
121                return (JsonArray ja) -> ProcessJsonArray
122                    .strToJava(ja, (SettingsRec<String, Stream<String>>) rec)
123                    .toArray(String[]::new);
124
125
126            case BASIC_TYPES.EXTENDED_OBJ:
127
128                return (JsonArray ja) -> ProcessJsonArray
129                    .objToJava(ja, (SettingsRec<T, Stream<T>>) rec)
130                    .toArray((int length) -> (T[]) Array.newInstance(rec.CLASS, length));
131
132            default: throw new UnreachableError();
133        }
134    }
135
136
137    // Converts a Java Boxed Stream to a Primitive Array.
138    static <T, U> U boxedStreamToPrimitiveArray(
139            final Stream<T>         boxedStream,
140            final JsonArray         ja,
141            final Class<T>          returnClass,
142            final ObjIntConsumer<T> arrayBuilder,
143            final U                 retArr
144        )
145    {
146        // Since the array-index is used inside of a LAMBDA, this "EffectivelyFinal" counter
147        // class becomes necessary.
148
149        final Counter counter = new Counter(-1);
150
151
152        // Don't forget, Stream's are not guaranteed to be processed in order, unless an
153        // explicit request is made using something like 'forEachOrdered'
154
155        boxedStream.forEachOrdered((T boxedPrimitive) ->
156        {
157            final int i = counter.addOne(); // "Final, or Effectively Final"
158
159            // A Primitive-Array (like int[], long[], boolean[] etc...) may not have null
160            if (boxedPrimitive == null)
161                throw new JsonNullPrimitiveArrException(ja, i, NUMBER, returnClass);
162
163            // The 'arrayBuilder' just assigns the value to the array[i]
164            arrayBuilder.accept(boxedPrimitive, i);
165        });
166    
167        return retArr;
168    }
169
170    
171    // REMEMBER: The 1-D Arrays ==> int[], long[], double[] are built directly from a 
172    //           PrimitiveStream using PrimStream.toArray, they don't need a "helper"
173
174
175    // @SuppressWarnings({"rawtypes", "unchecked"})
176    private static short[] array1DGeneratorShort(
177            final JsonArray                         ja,
178            final SettingsRec<Short, Stream<Short>> rec
179        )
180    {
181        final short[] retArrShort = new short[ja.size()];
182
183        return boxedStreamToPrimitiveArray(
184            ProcessJsonArray.numericToJava(ja, rec),
185            ja,
186            short.class,
187            (Short s, int i) -> retArrShort[i] = s.shortValue(),
188            retArrShort
189        );
190    }
191
192
193    // @SuppressWarnings({"rawtypes", "unchecked"})
194    private static byte[] array1DGeneratorByte(
195            final JsonArray                         ja,
196            final SettingsRec<Byte, Stream<Byte>>   rec
197        )
198    {
199        final byte[] retArrByte = new byte[ja.size()];
200
201        return boxedStreamToPrimitiveArray(
202            ProcessJsonArray.numericToJava(ja, rec),
203            ja,
204            byte.class,
205            (Byte s, int i) -> retArrByte[i] = s.byteValue(),
206            retArrByte
207        );
208    }
209
210
211    // @SuppressWarnings({"rawtypes", "unchecked"})
212    private static float[] array1DGeneratorFloat(
213            final JsonArray                         ja,
214            final SettingsRec<Float, Stream<Float>> rec
215        )
216    {
217        final float[] retArrFloat = new float[ja.size()];
218
219        return boxedStreamToPrimitiveArray(
220            ProcessJsonArray.numericToJava(ja, rec),
221            ja,
222            float.class,
223            (Float s, int i) -> retArrFloat[i] = s.floatValue(),
224            retArrFloat
225        );
226    }
227
228
229    // @SuppressWarnings({"rawtypes", "unchecked"})
230    private static boolean[] array1DGeneratorBoolean(
231            final JsonArray                             ja,
232            final SettingsRec<Boolean, Stream<Boolean>> rec
233        )
234    {
235        final boolean[] retArrBoolean = new boolean[ja.size()];
236
237        return boxedStreamToPrimitiveArray(
238            ProcessJsonArray.booleanToJava(ja, rec),
239            ja,
240            boolean.class,
241            (Boolean s, int i) -> retArrBoolean[i] = s.booleanValue(),
242            retArrBoolean
243        );
244    }
245
246}