content: /*
   * 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 static android.hardware.camera2.impl.CameraMetadataNative.*;
  import static com.android.internal.util.Preconditions.*;
  
  import android.hardware.camera2.impl.CameraMetadataNative;
  import android.util.Rational;
  
  /**
   * Static functions in order to help implementing various marshaler functionality.
   *
   * <p>The intention is to statically import everything from this file into another file when
   * implementing a new marshaler (or marshal queryable).</p>
   *
   * <p>The helpers are centered around providing primitive knowledge of the native types,
   * such as the native size, the managed class wrappers, and various precondition checks.</p>
   */
  public final class MarshalHelpers {
  
      public static final int SIZEOF_BYTE = 1;
      public static final int SIZEOF_INT32 = Integer.SIZE / Byte.SIZE;
      public static final int SIZEOF_INT64 = Long.SIZE / Byte.SIZE;
      public static final int SIZEOF_FLOAT = Float.SIZE / Byte.SIZE;
      public static final int SIZEOF_DOUBLE = Double.SIZE / Byte.SIZE;
      public static final int SIZEOF_RATIONAL = SIZEOF_INT32 * 2;
  
      /**
       * Get the size in bytes for the native camera metadata type.
       *
       * <p>This used to determine how many bytes it would take to encode/decode a single value
       * of that {@link nativeType}.</p>
       *
       * @param nativeType the native type, e.g.
       *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
       * @return size in bytes >= 1
       *
       * @throws UnsupportedOperationException if nativeType was not one of the built-in types
       */
      public static int getPrimitiveTypeSize(int nativeType) {
          switch (nativeType) {
              case TYPE_BYTE:
                  return SIZEOF_BYTE;
              case TYPE_INT32:
                  return SIZEOF_INT32;
              case TYPE_FLOAT:
                  return SIZEOF_FLOAT;
              case TYPE_INT64:
                  return SIZEOF_INT64;
              case TYPE_DOUBLE:
                  return SIZEOF_DOUBLE;
              case TYPE_RATIONAL:
                  return SIZEOF_RATIONAL;
          }
  
          throw new UnsupportedOperationException("Unknown type, can't get size for "
                  + nativeType);
      }
  
  
      /**
       * Ensure that the {@code klass} is one of the metadata-primitive classes.
       *
       * @param klass a non-{@code null} reference
       * @return {@code klass} instance
       *
       * @throws UnsupportedOperationException if klass was not one of the built-in classes
       * @throws NullPointerException if klass was null
       *
       * @see #isPrimitiveClass
       */
      public static <T> Class<T> checkPrimitiveClass(Class<T> klass) {
          checkNotNull(klass, "klass must not be null");
  
          if (isPrimitiveClass(klass)) {
              return klass;
          }
  
          throw new UnsupportedOperationException("Unsupported class '" + klass +
                  "'; expected a metadata primitive class");
      }
  
      /**
       * Checks whether or not {@code klass} is one of the metadata-primitive classes.
       *
       * <p>The following types (whether boxed or unboxed) are considered primitive:
       * <ul>
       * <li>byte
       * <li>int
       * <li>float
       * <li>double
       * <li>Rational
       * </ul>
       * </p>
       *
       * <p>This doesn't strictly follow the java understanding of primitive since
       * boxed objects are included, Rational is included, and other types such as char and
       * short are not included.</p>
       *
       * @param klass a {@link Class} instance; using {@code null} will return {@code false}
       * @return {@code true} if primitive, {@code false} otherwise
       */
      public static <T> boolean isPrimitiveClass(Class<T> klass) {
          if (klass == null) {
              return false;
          }
  
          if (klass == byte.class || klass == Byte.class) {
              return true;
          } else if (klass == int.class || klass == Integer.class) {
              return true;
          } else if (klass == float.class || klass == Float.class) {
              return true;
          } else if (klass == long.class || klass == Long.class) {
              return true;
          } else if (klass == double.class || klass == Double.class) {
              return true;
          } else if (klass == Rational.class) {
              return true;
          }
  
          return false;
      }
  
      /**
       * Wrap {@code klass} with its wrapper variant if it was a {@code Class} corresponding
       * to a Java primitive.
       *
       * <p>Non-primitive classes are passed through as-is.</p>
       *
       * <p>For example, for a primitive {@code int.class => Integer.class},
       * but for a non-primitive {@code Rational.class => Rational.class}.</p>
       *
       * @param klass a {@code Class} reference
       *
       * @return wrapped class object, or same class object if non-primitive
       */
      @SuppressWarnings("unchecked")
      public static <T> Class<T> wrapClassIfPrimitive(Class<T> klass) {
          if (klass == byte.class) {
              return (Class<T>)Byte.class;
          } else if (klass == int.class) {
              return (Class<T>)Integer.class;
          } else if (klass == float.class) {
              return (Class<T>)Float.class;
          } else if (klass == long.class) {
              return (Class<T>)Long.class;
          } else if (klass == double.class) {
              return (Class<T>)Double.class;
          }
  
          return klass;
      }
  
      /**
       * Return a human-readable representation of the {@code nativeType}, e.g. "TYPE_INT32"
       *
       * <p>Out-of-range values return a string with "UNKNOWN" as the prefix.</p>
       *
       * @param nativeType the native type
       *
       * @return human readable type name
       */
      public static String toStringNativeType(int nativeType) {
          switch (nativeType) {
              case TYPE_BYTE:
                  return "TYPE_BYTE";
              case TYPE_INT32:
                  return "TYPE_INT32";
              case TYPE_FLOAT:
                  return "TYPE_FLOAT";
              case TYPE_INT64:
                  return "TYPE_INT64";
              case TYPE_DOUBLE:
                  return "TYPE_DOUBLE";
              case TYPE_RATIONAL:
                  return "TYPE_RATIONAL";
          }
  
          return "UNKNOWN(" + nativeType + ")";
      }
  
      /**
       * Ensure that the {@code nativeType} is one of the native types supported
       * by {@link CameraMetadataNative}.
       *
       * @param nativeType the native type
       *
       * @return the native type
       *
       * @throws UnsupportedOperationException if the native type was invalid
       */
      public static int checkNativeType(int nativeType) {
          switch (nativeType) {
              case TYPE_BYTE:
              case TYPE_INT32:
              case TYPE_FLOAT:
              case TYPE_INT64:
              case TYPE_DOUBLE:
              case TYPE_RATIONAL:
                  return nativeType;
          }
  
          throw new UnsupportedOperationException("Unknown nativeType " + nativeType);
      }
  
      /**
       * Ensure that the expected and actual native types are equal.
       *
       * @param expectedNativeType the expected native type
       * @param actualNativeType the actual native type
       * @return the actual native type
       *
       * @throws UnsupportedOperationException if the types are not equal
       */
      public static int checkNativeTypeEquals(int expectedNativeType, int actualNativeType) {
          if (expectedNativeType != actualNativeType) {
              throw new UnsupportedOperationException(
                      String.format("Expected native type %d, but got %d",
                              expectedNativeType, actualNativeType));
          }
  
          return actualNativeType;
      }
  
      private MarshalHelpers() {
          throw new AssertionError();
      }
  }
  