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;
17
18import android.hardware.camera2.utils.TypeReference;
19
20import java.nio.ByteBuffer;
21
22import static android.hardware.camera2.marshal.MarshalHelpers.*;
23import static com.android.internal.util.Preconditions.*;
24
25/**
26 * Base class to marshal data to/from managed/native metadata byte buffers.
27 *
28 * <p>This class should not be created directly; an instance of it can be obtained
29 * using {@link MarshalQueryable#createMarshaler} for the same type {@code T} if the native type
30 * mapping for {@code T} {@link MarshalQueryable#isTypeMappingSupported supported}.</p>
31 *
32 * @param <T> the compile-time managed type
33 */
34public abstract class Marshaler<T> {
35
36    protected final TypeReference<T> mTypeReference;
37    protected final int mNativeType;
38
39    /**
40     * Instantiate a marshaler between a single managed/native type combination.
41     *
42     * <p>This particular managed/native type combination must be supported by
43     * {@link #isTypeMappingSupported}.</p>
44     *
45     * @param query an instance of {@link MarshalQueryable}
46     * @param typeReference the managed type reference
47     *        Must be one for which {@link #isTypeMappingSupported} returns {@code true}
48     * @param nativeType the native type, e.g.
49     *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
50     *        Must be one for which {@link #isTypeMappingSupported} returns {@code true}.
51     *
52     * @throws NullPointerException if any args were {@code null}
53     * @throws UnsupportedOperationException if the type mapping was not supported
54     */
55    protected Marshaler(
56            MarshalQueryable<T> query, TypeReference<T> typeReference, int nativeType) {
57        mTypeReference = checkNotNull(typeReference, "typeReference must not be null");
58        mNativeType = checkNativeType(nativeType);
59
60        if (!query.isTypeMappingSupported(typeReference, nativeType)) {
61            throw new UnsupportedOperationException(
62                    "Unsupported type marshaling for managed type "
63                            + typeReference + " and native type "
64                            + MarshalHelpers.toStringNativeType(nativeType));
65        }
66    }
67
68    /**
69     * Marshal the specified object instance (value) into a byte buffer.
70     *
71     * <p>Upon completion, the {@link ByteBuffer#position()} will have advanced by
72     * the {@link #calculateMarshalSize marshal size} of {@code value}.</p>
73     *
74     * @param value the value of type T that we wish to write into the byte buffer
75     * @param buffer the byte buffer into which the marshaled object will be written
76     */
77    public abstract void marshal(T value, ByteBuffer buffer);
78
79    /**
80     * Get the size in bytes for how much space would be required to write this {@code value}
81     * into a byte buffer using the given {@code nativeType}.
82     *
83     * <p>If the size of this {@code T} instance when serialized into a buffer is always constant,
84     * then this method will always return the same value (and particularly, it will return
85     * an equivalent value to {@link #getNativeSize()}.</p>
86     *
87     * <p>Overriding this method is a must when the size is {@link NATIVE_SIZE_DYNAMIC dynamic}.</p>
88     *
89     * @param value the value of type T that we wish to write into the byte buffer
90     * @return the size that would need to be written to the byte buffer
91     */
92    public int calculateMarshalSize(T value) {
93        int nativeSize = getNativeSize();
94
95        if (nativeSize == NATIVE_SIZE_DYNAMIC) {
96            throw new AssertionError("Override this function for dynamically-sized objects");
97        }
98
99        return nativeSize;
100    }
101
102    /**
103     * Unmarshal a new object instance from the byte buffer into its managed type.
104     *
105     * <p>Upon completion, the {@link ByteBuffer#position()} will have advanced by
106     * the {@link #calculateMarshalSize marshal size} of the returned {@code T} instance.</p>
107     *
108     * @param buffer the byte buffer, from which we will read the object
109     * @return a new instance of type T read from the byte buffer
110     */
111    public abstract T unmarshal(ByteBuffer buffer);
112
113    /**
114     * Used to denote variable-length data structures.
115     *
116     * <p>If the size is dynamic then we can't know ahead of time how big of a data structure
117     * to preallocate for e.g. arrays, so one object must be unmarshaled at a time.</p>
118     */
119    public static int NATIVE_SIZE_DYNAMIC = -1;
120
121    /**
122     * How many bytes a single instance of {@code T} will take up if marshalled to/from
123     * {@code nativeType}.
124     *
125     * <p>When unmarshaling data from native to managed, the instance {@code T} is not yet
126     * available. If the native size is always a fixed mapping regardless of the instance of
127     * {@code T} (e.g. if the type is not a container of some sort), it can be used to preallocate
128     * containers for {@code T} to avoid resizing them.</p>
129     *
130     * <p>In particular, the array marshaler takes advantage of this (when size is not dynamic)
131     * to preallocate arrays of the right length when unmarshaling an array {@code T[]}.</p>
132     *
133     * @return a size in bytes, or {@link #NATIVE_SIZE_DYNAMIC} if the size is dynamic
134     */
135    public abstract int getNativeSize();
136
137    /**
138     * The type reference for {@code T} for the managed type side of this marshaler.
139     */
140    public TypeReference<T> getTypeReference() {
141        return mTypeReference;
142    }
143
144    /** The native type corresponding to this marshaler for the native side of this marshaler.*/
145    public int getNativeType() {
146        return mNativeType;
147    }
148}
149