1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.hardware.camera2.marshal.impl;
17
18import android.hardware.camera2.impl.CameraMetadataNative;
19import android.hardware.camera2.marshal.Marshaler;
20import android.hardware.camera2.marshal.MarshalQueryable;
21import android.hardware.camera2.utils.TypeReference;
22import android.util.Rational;
23
24import static android.hardware.camera2.impl.CameraMetadataNative.*;
25import static android.hardware.camera2.marshal.MarshalHelpers.*;
26import static com.android.internal.util.Preconditions.*;
27
28import java.nio.ByteBuffer;
29
30/**
31 * Marshal/unmarshal built-in primitive types to and from a {@link ByteBuffer}.
32 *
33 * <p>The following list of type marshaling is supported:
34 * <ul>
35 * <li>byte <-> TYPE_BYTE
36 * <li>int <-> TYPE_INT32
37 * <li>long <-> TYPE_INT64
38 * <li>float <-> TYPE_FLOAT
39 * <li>double <-> TYPE_DOUBLE
40 * <li>Rational <-> TYPE_RATIONAL
41 * </ul>
42 * </p>
43 *
44 * <p>Due to the nature of generics, values are always boxed; this also means that both
45 * the boxed and unboxed types are supported (i.e. both {@code int} and {@code Integer}).</p>
46 *
47 * <p>Each managed type <!--(other than boolean)--> must correspond 1:1 to the native type
48 * (e.g. a byte will not map to a {@link CameraMetadataNative#TYPE_INT32 TYPE_INT32} or vice versa)
49 * for marshaling.</p>
50 */
51public final class MarshalQueryablePrimitive<T> implements MarshalQueryable<T> {
52
53    private class MarshalerPrimitive extends Marshaler<T> {
54        /** Always the wrapped class variant of the primitive class for {@code T} */
55        private final Class<T> mClass;
56
57        @SuppressWarnings("unchecked")
58        protected MarshalerPrimitive(TypeReference<T> typeReference, int nativeType) {
59            super(MarshalQueryablePrimitive.this, typeReference, nativeType);
60
61            // Turn primitives into wrappers, otherwise int.class.cast(Integer) will fail
62            mClass = wrapClassIfPrimitive((Class<T>)typeReference.getRawType());
63        }
64
65        @Override
66        public T unmarshal(ByteBuffer buffer) {
67            return mClass.cast(unmarshalObject(buffer));
68        }
69
70        @Override
71        public int calculateMarshalSize(T value) {
72            return getPrimitiveTypeSize(mNativeType);
73        }
74
75        @Override
76        public void marshal(T value, ByteBuffer buffer) {
77            if (value instanceof Integer) {
78                checkNativeTypeEquals(TYPE_INT32, mNativeType);
79                final int val = (Integer) value;
80                marshalPrimitive(val, buffer);
81            } else if (value instanceof Float) {
82                checkNativeTypeEquals(TYPE_FLOAT, mNativeType);
83                final float val = (Float) value;
84                marshalPrimitive(val, buffer);
85            } else if (value instanceof Long) {
86                checkNativeTypeEquals(TYPE_INT64, mNativeType);
87                final long val = (Long) value;
88                marshalPrimitive(val, buffer);
89            } else if (value instanceof Rational) {
90                checkNativeTypeEquals(TYPE_RATIONAL, mNativeType);
91                marshalPrimitive((Rational) value, buffer);
92            } else if (value instanceof Double) {
93                checkNativeTypeEquals(TYPE_DOUBLE, mNativeType);
94                final double val = (Double) value;
95                marshalPrimitive(val, buffer);
96            } else if (value instanceof Byte) {
97                checkNativeTypeEquals(TYPE_BYTE, mNativeType);
98                final byte val = (Byte) value;
99                marshalPrimitive(val, buffer);
100            } else {
101                throw new UnsupportedOperationException(
102                        "Can't marshal managed type " + mTypeReference);
103            }
104        }
105
106        private void marshalPrimitive(int value, ByteBuffer buffer) {
107            buffer.putInt(value);
108        }
109
110        private void marshalPrimitive(float value, ByteBuffer buffer) {
111            buffer.putFloat(value);
112        }
113
114        private void marshalPrimitive(double value, ByteBuffer buffer) {
115            buffer.putDouble(value);
116        }
117
118        private void marshalPrimitive(long value, ByteBuffer buffer) {
119            buffer.putLong(value);
120        }
121
122        private void marshalPrimitive(Rational value, ByteBuffer buffer) {
123            buffer.putInt(value.getNumerator());
124            buffer.putInt(value.getDenominator());
125        }
126
127        private void marshalPrimitive(byte value, ByteBuffer buffer) {
128            buffer.put(value);
129        }
130
131        private Object unmarshalObject(ByteBuffer buffer) {
132            switch (mNativeType) {
133                case TYPE_INT32:
134                    return buffer.getInt();
135                case TYPE_FLOAT:
136                    return buffer.getFloat();
137                case TYPE_INT64:
138                    return buffer.getLong();
139                case TYPE_RATIONAL:
140                    int numerator = buffer.getInt();
141                    int denominator = buffer.getInt();
142                    return new Rational(numerator, denominator);
143                case TYPE_DOUBLE:
144                    return buffer.getDouble();
145                case TYPE_BYTE:
146                    return buffer.get(); // getByte
147                default:
148                    throw new UnsupportedOperationException(
149                            "Can't unmarshal native type " + mNativeType);
150            }
151        }
152
153        @Override
154        public int getNativeSize() {
155            return getPrimitiveTypeSize(mNativeType);
156        }
157    }
158
159    @Override
160    public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
161        return new MarshalerPrimitive(managedType, nativeType);
162    }
163
164    @Override
165    public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
166        if (managedType.getType() instanceof Class<?>) {
167            Class<?> klass = (Class<?>)managedType.getType();
168
169            if (klass == byte.class || klass == Byte.class) {
170                return nativeType == TYPE_BYTE;
171            } else if (klass == int.class || klass == Integer.class) {
172                return nativeType == TYPE_INT32;
173            } else if (klass == float.class || klass == Float.class) {
174                return nativeType == TYPE_FLOAT;
175            } else if (klass == long.class || klass == Long.class) {
176                return nativeType == TYPE_INT64;
177            } else if (klass == double.class || klass == Double.class) {
178                return nativeType == TYPE_DOUBLE;
179            } else if (klass == Rational.class) {
180                return nativeType == TYPE_RATIONAL;
181            }
182        }
183        return false;
184    }
185}
186