Skip to content

Instantly share code, notes, and snippets.

@marcellogalhardo
Created September 26, 2024 13:27
Show Gist options
  • Save marcellogalhardo/bc965d663038dfea9c3adca9dc98f553 to your computer and use it in GitHub Desktop.
Save marcellogalhardo/bc965d663038dfea9c3adca9dc98f553 to your computer and use it in GitHub Desktop.
@file:Suppress(
"IMPLICIT_CAST_TO_ANY",
"UNCHECKED_CAST",
"IMPLICIT_CAST_TO_ANY",
"NOTHING_TO_INLINE",
"UNUSED_PARAMETER",
"KotlinOperator",
"KotlinConstantConditions",
"unused",
)
import android.os.Binder
import android.os.Bundle
import android.os.IBinder
import android.os.Parcelable
import android.util.Size
import android.util.SizeF
import android.util.SparseArray
import androidx.core.os.BundleCompat
import java.io.Serializable
object BundleUtils {
inline operator fun <reified T> get(bundle: Bundle, key: String): T =
with(bundle) {
return when (T::class) {
// Scalars
Boolean::class -> getBoolean(key)
Byte::class -> getByte(key)
Char::class -> getChar(key)
Double::class -> getDouble(key)
Float::class -> getFloat(key)
Int::class -> getInt(key)
Long::class -> getLong(key)
Short::class -> getShort(key)
// Scalar arrays
BooleanArray::class -> getBooleanArray(key)
ByteArray::class -> getByteArray(key)
CharArray::class -> getCharArray(key)
DoubleArray::class -> getDoubleArray(key)
FloatArray::class -> getFloatArray(key)
IntArray::class -> getIntArray(key)
LongArray::class -> getLongArray(key)
ShortArray::class -> getShortArray(key)
// References
Bundle::class -> getBundle(key)
CharSequence::class -> getCharSequence(key)
String::class -> getString(key)
// Reference arrays
Array::class -> {
val componentType = T::class.java.componentType!!
when {
Parcelable::class.java.isAssignableFrom(componentType) -> {
BundleCompat.getParcelableArray(
this,
key,
componentType as Class<Parcelable>
)
}
String::class.java.isAssignableFrom(componentType) -> {
getStringArray(key)
}
CharSequence::class.java.isAssignableFrom(componentType) -> {
getCharSequence(key)
}
Serializable::class.java.isAssignableFrom(componentType) -> {
BundleCompat.getSerializable(
this,
key,
componentType as Class<Serializable>
)
}
else -> {
val valueType = componentType.canonicalName
throw IllegalArgumentException(
"Illegal value array type $valueType for key \"$key\""
)
}
}
}
IBinder::class -> getBinder(key)
Size::class -> getSize(key)
SizeF::class -> getSizeF(key)
else ->
// Last resort.
when {
Parcelable::class.java.isAssignableFrom(T::class.java) ->
BundleCompat.getParcelable(
this,
key,
T::class.java as Class<out Parcelable>
)
Serializable::class.java.isAssignableFrom(T::class.java) ->
BundleCompat.getSerializable(
this,
key,
T::class.java as Class<out Serializable>
)
else -> {
val valueType = T::class.java.canonicalName
throw IllegalArgumentException(
"Illegal value type $valueType for key \"$key\""
)
}
}
}
as T
}
inline fun <reified T> put(bundle: Bundle, key: String, value: T) {
with(bundle) {
when (value) {
// Scalars
is Boolean -> putBoolean(key, value)
is Byte -> putByte(key, value)
is Char -> putChar(key, value)
is Double -> putDouble(key, value)
is Float -> putFloat(key, value)
is Int -> putInt(key, value)
is Long -> putLong(key, value)
is Short -> putShort(key, value)
// Scalar arrays
is BooleanArray -> putBooleanArray(key, value)
is ByteArray -> putByteArray(key, value)
is CharArray -> putCharArray(key, value)
is DoubleArray -> putDoubleArray(key, value)
is FloatArray -> putFloatArray(key, value)
is IntArray -> putIntArray(key, value)
is LongArray -> putLongArray(key, value)
is ShortArray -> putShortArray(key, value)
// References
is Bundle -> putBundle(key, value)
is CharSequence -> putCharSequence(key, value)
is Parcelable -> putParcelable(key, value)
is String -> putString(key, value)
// Reference arrays
is Array<*> -> {
val componentType = value!!::class.java.componentType!!
when {
Parcelable::class.java.isAssignableFrom(componentType) -> {
putParcelableArray(key, value as Array<Parcelable>)
}
String::class.java.isAssignableFrom(componentType) -> {
putStringArray(key, value as Array<String>)
}
CharSequence::class.java.isAssignableFrom(componentType) -> {
putCharSequenceArray(key, value as Array<CharSequence>)
}
Serializable::class.java.isAssignableFrom(componentType) -> {
putSerializable(key, componentType as Class<Serializable>)
}
else -> {
val valueType = componentType.canonicalName
throw IllegalArgumentException(
"Illegal value array type $valueType for key \"$key\""
)
}
}
}
// Last resort. Also we must check this after Array<*> as all arrays are
// serializable.
is Serializable -> putSerializable(key, value)
is IBinder -> putBinder(key, value)
is Size -> putSize(key, value)
is SizeF -> putSizeF(key, value)
else -> {
val valueType = T::class.java.canonicalName
throw IllegalArgumentException("Illegal value type $valueType for key \"$key\"")
}
}
}
}
@PublishedApi
internal inline fun <reified T : Any> Collection<*>.toArrayListUnsafe(): ArrayList<T> {
return if (this is ArrayList<*>) this as ArrayList<T> else ArrayList(this as Collection<T>)
}
inline fun isSupported(bundle: Bundle, value: Any?): Boolean {
return value == null || SUPPORTED_TYPES.any { type -> type.isInstance(value) }
}
@PublishedApi
internal val SUPPORTED_TYPES =
arrayOf( // baseBundle
Boolean::class,
BooleanArray::class,
Double::class,
DoubleArray::class,
Int::class,
IntArray::class,
Long::class,
LongArray::class,
String::class,
Array<String>::class, // bundle
Binder::class,
Bundle::class,
Byte::class,
ByteArray::class,
Char::class,
CharArray::class,
CharSequence::class,
Array<CharSequence>::class,
// type erasure ¯\_(ツ)_/¯, we won't eagerly check elements contents
ArrayList::class,
Float::class,
FloatArray::class,
Parcelable::class,
Array<Parcelable>::class,
Serializable::class,
Short::class,
ShortArray::class,
SparseArray::class,
Size::class,
SizeF::class,
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment