/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware.camera2.marshal; import android.hardware.camera2.utils.TypeReference; import java.nio.ByteBuffer; import static android.hardware.camera2.marshal.MarshalHelpers.*; import static com.android.internal.util.Preconditions.*; /** * Base class to marshal data to/from managed/native metadata byte buffers. * *

This class should not be created directly; an instance of it can be obtained * using {@link MarshalQueryable#createMarshaler} for the same type {@code T} if the native type * mapping for {@code T} {@link MarshalQueryable#isTypeMappingSupported supported}.

* * @param the compile-time managed type */ public abstract class Marshaler { protected final TypeReference mTypeReference; protected final int mNativeType; /** * Instantiate a marshaler between a single managed/native type combination. * *

This particular managed/native type combination must be supported by * {@link #isTypeMappingSupported}.

* * @param query an instance of {@link MarshalQueryable} * @param typeReference the managed type reference * Must be one for which {@link #isTypeMappingSupported} returns {@code true} * @param nativeType the native type, e.g. * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}. * Must be one for which {@link #isTypeMappingSupported} returns {@code true}. * * @throws NullPointerException if any args were {@code null} * @throws UnsupportedOperationException if the type mapping was not supported */ protected Marshaler( MarshalQueryable query, TypeReference typeReference, int nativeType) { mTypeReference = checkNotNull(typeReference, "typeReference must not be null"); mNativeType = checkNativeType(nativeType); if (!query.isTypeMappingSupported(typeReference, nativeType)) { throw new UnsupportedOperationException( "Unsupported type marshaling for managed type " + typeReference + " and native type " + MarshalHelpers.toStringNativeType(nativeType)); } } /** * Marshal the specified object instance (value) into a byte buffer. * *

Upon completion, the {@link ByteBuffer#position()} will have advanced by * the {@link #calculateMarshalSize marshal size} of {@code value}.

* * @param value the value of type T that we wish to write into the byte buffer * @param buffer the byte buffer into which the marshaled object will be written */ public abstract void marshal(T value, ByteBuffer buffer); /** * Get the size in bytes for how much space would be required to write this {@code value} * into a byte buffer using the given {@code nativeType}. * *

If the size of this {@code T} instance when serialized into a buffer is always constant, * then this method will always return the same value (and particularly, it will return * an equivalent value to {@link #getNativeSize()}.

* *

Overriding this method is a must when the size is {@link NATIVE_SIZE_DYNAMIC dynamic}.

* * @param value the value of type T that we wish to write into the byte buffer * @return the size that would need to be written to the byte buffer */ public int calculateMarshalSize(T value) { int nativeSize = getNativeSize(); if (nativeSize == NATIVE_SIZE_DYNAMIC) { throw new AssertionError("Override this function for dynamically-sized objects"); } return nativeSize; } /** * Unmarshal a new object instance from the byte buffer into its managed type. * *

Upon completion, the {@link ByteBuffer#position()} will have advanced by * the {@link #calculateMarshalSize marshal size} of the returned {@code T} instance.

* * @param buffer the byte buffer, from which we will read the object * @return a new instance of type T read from the byte buffer */ public abstract T unmarshal(ByteBuffer buffer); /** * Used to denote variable-length data structures. * *

If the size is dynamic then we can't know ahead of time how big of a data structure * to preallocate for e.g. arrays, so one object must be unmarshaled at a time.

*/ public static int NATIVE_SIZE_DYNAMIC = -1; /** * How many bytes a single instance of {@code T} will take up if marshalled to/from * {@code nativeType}. * *

When unmarshaling data from native to managed, the instance {@code T} is not yet * available. If the native size is always a fixed mapping regardless of the instance of * {@code T} (e.g. if the type is not a container of some sort), it can be used to preallocate * containers for {@code T} to avoid resizing them.

* *

In particular, the array marshaler takes advantage of this (when size is not dynamic) * to preallocate arrays of the right length when unmarshaling an array {@code T[]}.

* * @return a size in bytes, or {@link #NATIVE_SIZE_DYNAMIC} if the size is dynamic */ public abstract int getNativeSize(); /** * The type reference for {@code T} for the managed type side of this marshaler. */ public TypeReference getTypeReference() { return mTypeReference; } /** The native type corresponding to this marshaler for the native side of this marshaler.*/ public int getNativeType() { return mNativeType; } }