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.marshal.Marshaler;
19import android.hardware.camera2.marshal.MarshalQueryable;
20import android.hardware.camera2.marshal.MarshalRegistry;
21import android.hardware.camera2.utils.TypeReference;
22import android.util.Pair;
23
24import java.lang.reflect.Constructor;
25import java.lang.reflect.InvocationTargetException;
26import java.lang.reflect.ParameterizedType;
27import java.lang.reflect.Type;
28import java.nio.ByteBuffer;
29
30/**
31 * Marshal {@link Pair} to/from any native type
32 */
33public class MarshalQueryablePair<T1, T2>
34        implements MarshalQueryable<Pair<T1, T2>> {
35
36    private class MarshalerPair extends Marshaler<Pair<T1, T2>> {
37        private final Class<? super Pair<T1, T2>> mClass;
38        private final Constructor<Pair<T1, T2>> mConstructor;
39        /** Marshal the {@code T1} inside of {@code Pair<T1, T2>} */
40        private final Marshaler<T1> mNestedTypeMarshalerFirst;
41        /** Marshal the {@code T1} inside of {@code Pair<T1, T2>} */
42        private final Marshaler<T2> mNestedTypeMarshalerSecond;
43
44        @SuppressWarnings("unchecked")
45        protected MarshalerPair(TypeReference<Pair<T1, T2>> typeReference,
46                int nativeType) {
47            super(MarshalQueryablePair.this, typeReference, nativeType);
48
49            mClass = typeReference.getRawType();
50
51            /*
52             * Lookup the actual type arguments, e.g. Pair<Integer, Float> --> [Integer, Float]
53             * and then get the marshalers for that managed type.
54             */
55            ParameterizedType paramType;
56            try {
57                paramType = (ParameterizedType) typeReference.getType();
58            } catch (ClassCastException e) {
59                throw new AssertionError("Raw use of Pair is not supported", e);
60            }
61
62            // Get type marshaler for T1
63            {
64                Type actualTypeArgument = paramType.getActualTypeArguments()[0];
65
66                TypeReference<?> actualTypeArgToken =
67                        TypeReference.createSpecializedTypeReference(actualTypeArgument);
68
69                mNestedTypeMarshalerFirst = (Marshaler<T1>)MarshalRegistry.getMarshaler(
70                        actualTypeArgToken, mNativeType);
71            }
72            // Get type marshaler for T2
73            {
74                Type actualTypeArgument = paramType.getActualTypeArguments()[1];
75
76                TypeReference<?> actualTypeArgToken =
77                        TypeReference.createSpecializedTypeReference(actualTypeArgument);
78
79                mNestedTypeMarshalerSecond = (Marshaler<T2>)MarshalRegistry.getMarshaler(
80                        actualTypeArgToken, mNativeType);
81            }
82            try {
83                mConstructor = (Constructor<Pair<T1, T2>>)mClass.getConstructor(
84                        Object.class, Object.class);
85            } catch (NoSuchMethodException e) {
86                throw new AssertionError(e);
87            }
88        }
89
90        @Override
91        public void marshal(Pair<T1, T2> value, ByteBuffer buffer) {
92            if (value.first == null) {
93                throw new UnsupportedOperationException("Pair#first must not be null");
94            } else if (value.second == null) {
95                throw new UnsupportedOperationException("Pair#second must not be null");
96            }
97
98            mNestedTypeMarshalerFirst.marshal(value.first, buffer);
99            mNestedTypeMarshalerSecond.marshal(value.second, buffer);
100        }
101
102        @Override
103        public Pair<T1, T2> unmarshal(ByteBuffer buffer) {
104            T1 first = mNestedTypeMarshalerFirst.unmarshal(buffer);
105            T2 second = mNestedTypeMarshalerSecond.unmarshal(buffer);
106
107            try {
108                return mConstructor.newInstance(first, second);
109            } catch (InstantiationException e) {
110                throw new AssertionError(e);
111            } catch (IllegalAccessException e) {
112                throw new AssertionError(e);
113            } catch (IllegalArgumentException e) {
114                throw new AssertionError(e);
115            } catch (InvocationTargetException e) {
116                throw new AssertionError(e);
117            }
118        }
119
120        @Override
121        public int getNativeSize() {
122            int firstSize = mNestedTypeMarshalerFirst.getNativeSize();
123            int secondSize = mNestedTypeMarshalerSecond.getNativeSize();
124
125            if (firstSize != NATIVE_SIZE_DYNAMIC && secondSize != NATIVE_SIZE_DYNAMIC) {
126                return firstSize + secondSize;
127            } else {
128                return NATIVE_SIZE_DYNAMIC;
129            }
130        }
131
132        @Override
133        public int calculateMarshalSize(Pair<T1, T2> value) {
134            int nativeSize = getNativeSize();
135
136            if (nativeSize != NATIVE_SIZE_DYNAMIC) {
137                return nativeSize;
138            } else {
139                int firstSize = mNestedTypeMarshalerFirst.calculateMarshalSize(value.first);
140                int secondSize = mNestedTypeMarshalerSecond.calculateMarshalSize(value.second);
141
142                return firstSize + secondSize;
143            }
144        }
145    }
146
147    @Override
148    public Marshaler<Pair<T1, T2>> createMarshaler(TypeReference<Pair<T1, T2>> managedType,
149            int nativeType) {
150        return new MarshalerPair(managedType, nativeType);
151    }
152
153    @Override
154    public boolean isTypeMappingSupported(TypeReference<Pair<T1, T2>> managedType, int nativeType) {
155        return (Pair.class.equals(managedType.getRawType()));
156    }
157
158}
159