diff --git a/library/core/api/core.api b/library/core/api/core.api index 52a6929..e11157c 100644 --- a/library/core/api/core.api +++ b/library/core/api/core.api @@ -1,18 +1,20 @@ public abstract class io/matthewnelson/encoding/core/Decoder { public static final field Companion Lio/matthewnelson/encoding/core/Decoder$Companion; public synthetic fun (Lio/matthewnelson/encoding/core/EncoderDecoder$Config;Lkotlin/jvm/internal/DefaultConstructorMarker;)V - public static final fun decodeBuffered (Ljava/lang/CharSequence;ILio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function3;)J public static final fun decodeBuffered (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function3;)J - public static final fun decodeBuffered (Ljava/lang/CharSequence;[BLio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function3;)J - public static final fun decodeBuffered ([CILio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function3;)J - public static final fun decodeBuffered ([CLio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function3;)J - public static final fun decodeBuffered ([C[BLio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function3;)J - public static final fun decodeBufferedAsync (Ljava/lang/CharSequence;ILio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun decodeBuffered (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;ZILkotlin/jvm/functions/Function3;)J + public static final fun decodeBuffered (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;ZLkotlin/jvm/functions/Function3;)J + public static final fun decodeBuffered (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;Z[BLkotlin/jvm/functions/Function3;)J + public static final fun decodeBuffered ([CLio/matthewnelson/encoding/core/Decoder;ZILkotlin/jvm/functions/Function3;)J + public static final fun decodeBuffered ([CLio/matthewnelson/encoding/core/Decoder;ZLkotlin/jvm/functions/Function3;)J + public static final fun decodeBuffered ([CLio/matthewnelson/encoding/core/Decoder;Z[BLkotlin/jvm/functions/Function3;)J public static final fun decodeBufferedAsync (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static final fun decodeBufferedAsync (Ljava/lang/CharSequence;[BLio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static final fun decodeBufferedAsync ([CILio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static final fun decodeBufferedAsync ([CLio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static final fun decodeBufferedAsync ([C[BLio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun decodeBufferedAsync (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;ZILkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun decodeBufferedAsync (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;ZLkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun decodeBufferedAsync (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;Z[BLkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun decodeBufferedAsync ([CLio/matthewnelson/encoding/core/Decoder;ZILkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun decodeBufferedAsync ([CLio/matthewnelson/encoding/core/Decoder;ZLkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun decodeBufferedAsync ([CLio/matthewnelson/encoding/core/Decoder;Z[BLkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun decodeToByteArray (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;)[B public static final fun decodeToByteArray ([BLio/matthewnelson/encoding/core/Decoder;)[B public static final fun decodeToByteArray ([CLio/matthewnelson/encoding/core/Decoder;)[B @@ -25,18 +27,20 @@ public abstract class io/matthewnelson/encoding/core/Decoder { } public final class io/matthewnelson/encoding/core/Decoder$Companion { - public final fun decodeBuffered (Ljava/lang/CharSequence;ILio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function3;)J public final fun decodeBuffered (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function3;)J - public final fun decodeBuffered (Ljava/lang/CharSequence;[BLio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function3;)J - public final fun decodeBuffered ([CILio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function3;)J - public final fun decodeBuffered ([CLio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function3;)J - public final fun decodeBuffered ([C[BLio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function3;)J - public final fun decodeBufferedAsync (Ljava/lang/CharSequence;ILio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun decodeBuffered (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;ZILkotlin/jvm/functions/Function3;)J + public final fun decodeBuffered (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;ZLkotlin/jvm/functions/Function3;)J + public final fun decodeBuffered (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;Z[BLkotlin/jvm/functions/Function3;)J + public final fun decodeBuffered ([CLio/matthewnelson/encoding/core/Decoder;ZILkotlin/jvm/functions/Function3;)J + public final fun decodeBuffered ([CLio/matthewnelson/encoding/core/Decoder;ZLkotlin/jvm/functions/Function3;)J + public final fun decodeBuffered ([CLio/matthewnelson/encoding/core/Decoder;Z[BLkotlin/jvm/functions/Function3;)J public final fun decodeBufferedAsync (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public final fun decodeBufferedAsync (Ljava/lang/CharSequence;[BLio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public final fun decodeBufferedAsync ([CILio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public final fun decodeBufferedAsync ([CLio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public final fun decodeBufferedAsync ([C[BLio/matthewnelson/encoding/core/Decoder;Lkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun decodeBufferedAsync (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;ZILkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun decodeBufferedAsync (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;ZLkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun decodeBufferedAsync (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;Z[BLkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun decodeBufferedAsync ([CLio/matthewnelson/encoding/core/Decoder;ZILkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun decodeBufferedAsync ([CLio/matthewnelson/encoding/core/Decoder;ZLkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun decodeBufferedAsync ([CLio/matthewnelson/encoding/core/Decoder;Z[BLkotlin/jvm/functions/Function4;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun decodeToByteArray (Ljava/lang/CharSequence;Lio/matthewnelson/encoding/core/Decoder;)[B public final fun decodeToByteArray ([BLio/matthewnelson/encoding/core/Decoder;)[B public final fun decodeToByteArray ([CLio/matthewnelson/encoding/core/Decoder;)[B diff --git a/library/core/api/core.klib.api b/library/core/api/core.klib.api index d4180d8..6019ab4 100644 --- a/library/core/api/core.klib.api +++ b/library/core/api/core.klib.api @@ -217,21 +217,23 @@ sealed class <#A: io.matthewnelson.encoding.core/EncoderDecoder.Config> io.matth final object Companion { // io.matthewnelson.encoding.core/Decoder.Companion|null[0] final fun (kotlin/ByteArray).decodeToByteArray(io.matthewnelson.encoding.core/Decoder<*>): kotlin/ByteArray // io.matthewnelson.encoding.core/Decoder.Companion.decodeToByteArray|decodeToByteArray@kotlin.ByteArray(io.matthewnelson.encoding.core.Decoder<*>){}[0] final fun (kotlin/ByteArray).decodeToByteArrayOrNull(io.matthewnelson.encoding.core/Decoder<*>): kotlin/ByteArray? // io.matthewnelson.encoding.core/Decoder.Companion.decodeToByteArrayOrNull|decodeToByteArrayOrNull@kotlin.ByteArray(io.matthewnelson.encoding.core.Decoder<*>){}[0] - final fun (kotlin/CharArray).decodeBuffered(kotlin/ByteArray, io.matthewnelson.encoding.core/Decoder<*>, kotlin/Function3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBuffered|decodeBuffered@kotlin.CharArray(kotlin.ByteArray;io.matthewnelson.encoding.core.Decoder<*>;kotlin.Function3){}[0] - final fun (kotlin/CharArray).decodeBuffered(kotlin/Int, io.matthewnelson.encoding.core/Decoder<*>, kotlin/Function3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBuffered|decodeBuffered@kotlin.CharArray(kotlin.Int;io.matthewnelson.encoding.core.Decoder<*>;kotlin.Function3){}[0] + final fun (kotlin/CharArray).decodeBuffered(io.matthewnelson.encoding.core/Decoder<*>, kotlin/Boolean, kotlin/ByteArray, kotlin/Function3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBuffered|decodeBuffered@kotlin.CharArray(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Boolean;kotlin.ByteArray;kotlin.Function3){}[0] + final fun (kotlin/CharArray).decodeBuffered(io.matthewnelson.encoding.core/Decoder<*>, kotlin/Boolean, kotlin/Int, kotlin/Function3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBuffered|decodeBuffered@kotlin.CharArray(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Boolean;kotlin.Int;kotlin.Function3){}[0] final fun (kotlin/CharArray).decodeToByteArray(io.matthewnelson.encoding.core/Decoder<*>): kotlin/ByteArray // io.matthewnelson.encoding.core/Decoder.Companion.decodeToByteArray|decodeToByteArray@kotlin.CharArray(io.matthewnelson.encoding.core.Decoder<*>){}[0] final fun (kotlin/CharArray).decodeToByteArrayOrNull(io.matthewnelson.encoding.core/Decoder<*>): kotlin/ByteArray? // io.matthewnelson.encoding.core/Decoder.Companion.decodeToByteArrayOrNull|decodeToByteArrayOrNull@kotlin.CharArray(io.matthewnelson.encoding.core.Decoder<*>){}[0] - final fun (kotlin/CharSequence).decodeBuffered(kotlin/ByteArray, io.matthewnelson.encoding.core/Decoder<*>, kotlin/Function3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBuffered|decodeBuffered@kotlin.CharSequence(kotlin.ByteArray;io.matthewnelson.encoding.core.Decoder<*>;kotlin.Function3){}[0] - final fun (kotlin/CharSequence).decodeBuffered(kotlin/Int, io.matthewnelson.encoding.core/Decoder<*>, kotlin/Function3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBuffered|decodeBuffered@kotlin.CharSequence(kotlin.Int;io.matthewnelson.encoding.core.Decoder<*>;kotlin.Function3){}[0] + final fun (kotlin/CharSequence).decodeBuffered(io.matthewnelson.encoding.core/Decoder<*>, kotlin/Boolean, kotlin/ByteArray, kotlin/Function3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBuffered|decodeBuffered@kotlin.CharSequence(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Boolean;kotlin.ByteArray;kotlin.Function3){}[0] + final fun (kotlin/CharSequence).decodeBuffered(io.matthewnelson.encoding.core/Decoder<*>, kotlin/Boolean, kotlin/Int, kotlin/Function3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBuffered|decodeBuffered@kotlin.CharSequence(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Boolean;kotlin.Int;kotlin.Function3){}[0] final fun (kotlin/CharSequence).decodeToByteArray(io.matthewnelson.encoding.core/Decoder<*>): kotlin/ByteArray // io.matthewnelson.encoding.core/Decoder.Companion.decodeToByteArray|decodeToByteArray@kotlin.CharSequence(io.matthewnelson.encoding.core.Decoder<*>){}[0] final fun (kotlin/CharSequence).decodeToByteArrayOrNull(io.matthewnelson.encoding.core/Decoder<*>): kotlin/ByteArray? // io.matthewnelson.encoding.core/Decoder.Companion.decodeToByteArrayOrNull|decodeToByteArrayOrNull@kotlin.CharSequence(io.matthewnelson.encoding.core.Decoder<*>){}[0] - final inline fun (kotlin/CharArray).decodeBuffered(io.matthewnelson.encoding.core/Decoder<*>, noinline kotlin/Function3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBuffered|decodeBuffered@kotlin.CharArray(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Function3){}[0] + final inline fun (kotlin/CharArray).decodeBuffered(io.matthewnelson.encoding.core/Decoder<*>, kotlin/Boolean, noinline kotlin/Function3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBuffered|decodeBuffered@kotlin.CharArray(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Boolean;kotlin.Function3){}[0] + final inline fun (kotlin/CharSequence).decodeBuffered(io.matthewnelson.encoding.core/Decoder<*>, kotlin/Boolean, noinline kotlin/Function3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBuffered|decodeBuffered@kotlin.CharSequence(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Boolean;kotlin.Function3){}[0] final inline fun (kotlin/CharSequence).decodeBuffered(io.matthewnelson.encoding.core/Decoder<*>, noinline kotlin/Function3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBuffered|decodeBuffered@kotlin.CharSequence(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Function3){}[0] - final suspend fun (kotlin/CharArray).decodeBufferedAsync(kotlin/ByteArray, io.matthewnelson.encoding.core/Decoder<*>, kotlin.coroutines/SuspendFunction3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBufferedAsync|decodeBufferedAsync@kotlin.CharArray(kotlin.ByteArray;io.matthewnelson.encoding.core.Decoder<*>;kotlin.coroutines.SuspendFunction3){}[0] - final suspend fun (kotlin/CharArray).decodeBufferedAsync(kotlin/Int, io.matthewnelson.encoding.core/Decoder<*>, kotlin.coroutines/SuspendFunction3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBufferedAsync|decodeBufferedAsync@kotlin.CharArray(kotlin.Int;io.matthewnelson.encoding.core.Decoder<*>;kotlin.coroutines.SuspendFunction3){}[0] - final suspend fun (kotlin/CharSequence).decodeBufferedAsync(kotlin/ByteArray, io.matthewnelson.encoding.core/Decoder<*>, kotlin.coroutines/SuspendFunction3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBufferedAsync|decodeBufferedAsync@kotlin.CharSequence(kotlin.ByteArray;io.matthewnelson.encoding.core.Decoder<*>;kotlin.coroutines.SuspendFunction3){}[0] - final suspend fun (kotlin/CharSequence).decodeBufferedAsync(kotlin/Int, io.matthewnelson.encoding.core/Decoder<*>, kotlin.coroutines/SuspendFunction3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBufferedAsync|decodeBufferedAsync@kotlin.CharSequence(kotlin.Int;io.matthewnelson.encoding.core.Decoder<*>;kotlin.coroutines.SuspendFunction3){}[0] - final suspend inline fun (kotlin/CharArray).decodeBufferedAsync(io.matthewnelson.encoding.core/Decoder<*>, noinline kotlin.coroutines/SuspendFunction3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBufferedAsync|decodeBufferedAsync@kotlin.CharArray(io.matthewnelson.encoding.core.Decoder<*>;kotlin.coroutines.SuspendFunction3){}[0] + final suspend fun (kotlin/CharArray).decodeBufferedAsync(io.matthewnelson.encoding.core/Decoder<*>, kotlin/Boolean, kotlin/ByteArray, kotlin.coroutines/SuspendFunction3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBufferedAsync|decodeBufferedAsync@kotlin.CharArray(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Boolean;kotlin.ByteArray;kotlin.coroutines.SuspendFunction3){}[0] + final suspend fun (kotlin/CharArray).decodeBufferedAsync(io.matthewnelson.encoding.core/Decoder<*>, kotlin/Boolean, kotlin/Int, kotlin.coroutines/SuspendFunction3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBufferedAsync|decodeBufferedAsync@kotlin.CharArray(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Boolean;kotlin.Int;kotlin.coroutines.SuspendFunction3){}[0] + final suspend fun (kotlin/CharSequence).decodeBufferedAsync(io.matthewnelson.encoding.core/Decoder<*>, kotlin/Boolean, kotlin/ByteArray, kotlin.coroutines/SuspendFunction3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBufferedAsync|decodeBufferedAsync@kotlin.CharSequence(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Boolean;kotlin.ByteArray;kotlin.coroutines.SuspendFunction3){}[0] + final suspend fun (kotlin/CharSequence).decodeBufferedAsync(io.matthewnelson.encoding.core/Decoder<*>, kotlin/Boolean, kotlin/Int, kotlin.coroutines/SuspendFunction3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBufferedAsync|decodeBufferedAsync@kotlin.CharSequence(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Boolean;kotlin.Int;kotlin.coroutines.SuspendFunction3){}[0] + final suspend inline fun (kotlin/CharArray).decodeBufferedAsync(io.matthewnelson.encoding.core/Decoder<*>, kotlin/Boolean, noinline kotlin.coroutines/SuspendFunction3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBufferedAsync|decodeBufferedAsync@kotlin.CharArray(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Boolean;kotlin.coroutines.SuspendFunction3){}[0] + final suspend inline fun (kotlin/CharSequence).decodeBufferedAsync(io.matthewnelson.encoding.core/Decoder<*>, kotlin/Boolean, noinline kotlin.coroutines/SuspendFunction3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBufferedAsync|decodeBufferedAsync@kotlin.CharSequence(io.matthewnelson.encoding.core.Decoder<*>;kotlin.Boolean;kotlin.coroutines.SuspendFunction3){}[0] final suspend inline fun (kotlin/CharSequence).decodeBufferedAsync(io.matthewnelson.encoding.core/Decoder<*>, noinline kotlin.coroutines/SuspendFunction3): kotlin/Long // io.matthewnelson.encoding.core/Decoder.Companion.decodeBufferedAsync|decodeBufferedAsync@kotlin.CharSequence(io.matthewnelson.encoding.core.Decoder<*>;kotlin.coroutines.SuspendFunction3){}[0] } } diff --git a/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/Decoder.kt b/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/Decoder.kt index 98536ea..a974385 100644 --- a/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/Decoder.kt +++ b/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/Decoder.kt @@ -304,9 +304,10 @@ public sealed class Decoder(public val config: C) { * equal to the [DEFAULT_BUFFER_SIZE], then an array of that size will be allocated * and [action] is only invoked once (single-shot decoding). In the event that * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] throws its [EncodingSizeException] - * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]), or is greater - * than [DEFAULT_BUFFER_SIZE], then this function will always stream decode to a - * buffer while flushing to [action] until the decoding operation has completed. + * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]) while [throwOnOverflow] + * is `false`, or its return value is greater than [DEFAULT_BUFFER_SIZE], then this + * function will always stream decode to a buffer while flushing to [action] until + * the decoding operation has completed. * * **NOTE:** Documented exceptions thrown by this function do not include those * for which [action] may throw. @@ -315,7 +316,7 @@ public sealed class Decoder(public val config: C) { * * "/path/to/file.txt".toFile().openWrite(excl = null).use { stream -> * val n = "Some long string" - * .decodeBuffered(UTF8, stream::write) + * .decodeBuffered(UTF8, false, stream::write) * println("Wrote $n UTF-8 bytes to file.txt") * } * @@ -323,7 +324,7 @@ public sealed class Decoder(public val config: C) { * * val d = SHA256() * "SGVsbG8gV29ybGQh" - * .decodeBuffered(Base64.Default, d::update) + * .decodeBuffered(Base64.Default, false, d::update) * // ... * * **NOTE:** The [Decoder] implementation must be compatible with version `2.6.0+` @@ -335,6 +336,9 @@ public sealed class Decoder(public val config: C) { * and [decodeBufferedAsync] APIs. * * @param [decoder] The [Decoder] to use. + * @param [throwOnOverflow] If `true` and [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * throws an [EncodingSizeException], it will be re-thrown. If `false`, the exception + * will be swallowed and stream decoding to the buffer will continue. * @param [action] The function to flush the buffer to; a destination to "write" * decoded data to whereby `len` is the number of bytes within `buf`, starting * at index `offset`, to "write". @@ -347,13 +351,16 @@ public sealed class Decoder(public val config: C) { * * @throws [EncodingException] If decoding failed, such as the [decoder] rejecting * an invalid character or sequence. + * @throws [EncodingSizeException] If [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * threw its exception and [throwOnOverflow] is `true`. * */ @JvmStatic @Throws(EncodingException::class) public inline fun CharSequence.decodeBuffered( decoder: Decoder<*>, + throwOnOverflow: Boolean, noinline action: (buf: ByteArray, offset: Int, len: Int) -> Unit, - ): Long = decodeBuffered(DEFAULT_BUFFER_SIZE, decoder, action) + ): Long = decodeBuffered(decoder, throwOnOverflow, DEFAULT_BUFFER_SIZE, action) /** * Decode a [CharSequence] using a maximum array size of [maxBufSize]. @@ -363,9 +370,10 @@ public sealed class Decoder(public val config: C) { * equal to the [maxBufSize], then an array of that size will be allocated * and [action] is only invoked once (single-shot decoding). In the event that * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] throws its [EncodingSizeException] - * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]), or is greater - * than [maxBufSize], then this function will always stream decode to a - * buffer while flushing to [action] until the decoding operation has completed. + * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]) while [throwOnOverflow] + * is `false`, or its return value is greater than [maxBufSize], then this + * function will always stream decode to a buffer while flushing to [action] until + * the decoding operation has completed. * * **NOTE:** Documented exceptions thrown by this function do not include those * for which [action] may throw. @@ -374,7 +382,7 @@ public sealed class Decoder(public val config: C) { * * "/path/to/file.txt".toFile().openWrite(excl = null).use { stream -> * val n = "Some string" - * .decodeBuffered(1024, UTF8, stream::write) + * .decodeBuffered(UTF8, false, 1024, stream::write) * println("Wrote $n UTF-8 bytes to file.txt") * } * @@ -382,7 +390,7 @@ public sealed class Decoder(public val config: C) { * * val d = SHA256() * "SGVsbG8gV29ybGQh" - * .decodeBuffered(1024, Base64.Default, d::update) + * .decodeBuffered(Base64.Default, false, 1024, d::update) * // ... * * **NOTE:** The [Decoder] implementation must be compatible with version `2.6.0+` @@ -393,9 +401,12 @@ public sealed class Decoder(public val config: C) { * library that have not updated yet may fail when using them with [decodeBuffered] * and [decodeBufferedAsync] APIs. * + * @param [decoder] The [Decoder] to use. + * @param [throwOnOverflow] If `true` and [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * throws an [EncodingSizeException], it will be re-thrown. If `false`, the exception + * will be swallowed and stream decoding to the buffer will continue. * @param [maxBufSize] The maximum size array this function will allocate. Must * be greater than [EncoderDecoder.Config.maxDecodeEmit]. - * @param [decoder] The [Decoder] to use. * @param [action] The function to flush the buffer to; a destination to "write" * decoded data to whereby `len` is the number of bytes within `buf`, starting * at index `offset`, to "write". @@ -410,16 +421,20 @@ public sealed class Decoder(public val config: C) { * an invalid character or sequence. * @throws [IllegalArgumentException] If [maxBufSize] is less than or equal to * [EncoderDecoder.Config.maxDecodeEmit]. + * @throws [EncodingSizeException] If [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * threw its exception and [throwOnOverflow] is `true`. * */ @JvmStatic @Throws(EncodingException::class) public fun CharSequence.decodeBuffered( - maxBufSize: Int, decoder: Decoder<*>, + throwOnOverflow: Boolean, + maxBufSize: Int, action: (buf: ByteArray, offset: Int, len: Int) -> Unit, ): Long = decoder.decodeBuffered( buf = null, maxBufSize = maxBufSize, + throwOnOverflow = throwOnOverflow, _get = ::get, _input = { DecoderInput(this) }, _action = action, @@ -432,9 +447,10 @@ public sealed class Decoder(public val config: C) { * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] is less than or equal to the [buf] * size, then [action] is only invoked once (single-shot decoding). In the event that * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] throws its [EncodingSizeException] - * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]), or is greater - * than [buf] size, then this function will always stream decode to [buf] while - * flushing to [action] until the decoding operation has completed. + * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]) while [throwOnOverflow] + * is `false`, or its return value is greater than [buf] size, then this + * function will always stream decode to a buffer while flushing to [action] until + * the decoding operation has completed. * * **NOTE:** Documented exceptions thrown by this function do not include those * for which [action] may throw. @@ -447,9 +463,9 @@ public sealed class Decoder(public val config: C) { * "/path/to/file.txt".toFile().openWrite(excl = null).use { stream -> * val buf = ByteArray(DEFAULT_BUFFER_SIZE) * var n = "Some string" - * .decodeBuffered(buf, UTF8, stream::write) + * .decodeBuffered(UTF8, false, buf, stream::write) * n += "Some other string" - * .decodeBuffered(buf, UTF8, stream::write) + * .decodeBuffered(UTF8, false, buf, stream::write) * println("Wrote $n UTF-8 bytes to file.txt") * } * @@ -458,9 +474,9 @@ public sealed class Decoder(public val config: C) { * val d = SHA256() * val buf = ByteArray(DEFAULT_BUFFER_SIZE) * "SGVsbG8gV29ybGQh" - * .decodeBuffered(buf, Base64.Default, d::update) + * .decodeBuffered(Base64.Default, false, buf, d::update) * "SGVsbG8gV29ybGQh" - * .decodeBuffered(buf, Base64.Default, d::update) + * .decodeBuffered(Base64.Default, false, buf, d::update) * // ... * * **NOTE:** The [Decoder] implementation must be compatible with version `2.6.0+` @@ -471,9 +487,12 @@ public sealed class Decoder(public val config: C) { * library that have not updated yet may fail when using them with [decodeBuffered] * and [decodeBufferedAsync] APIs. * + * @param [decoder] The [Decoder] to use. + * @param [throwOnOverflow] If `true` and [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * throws an [EncodingSizeException], it will be re-thrown. If `false`, the exception + * will be swallowed and stream decoding to the buffer will continue. * @param [buf] The pre-allocated array to use as the buffer. Its size must be * greater than [EncoderDecoder.Config.maxDecodeEmit]. - * @param [decoder] The [Decoder] to use. * @param [action] The function to flush the buffer to; a destination to "write" * decoded data to whereby `len` is the number of bytes within `buf`, starting * at index `offset`, to "write". @@ -486,18 +505,22 @@ public sealed class Decoder(public val config: C) { * * @throws [EncodingException] If decoding failed, such as the [decoder] rejecting * an invalid character or sequence. + * @throws [EncodingSizeException] If [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * threw its exception and [throwOnOverflow] is `true`. * @throws [IllegalArgumentException] If [buf] size is less than or equal to * [EncoderDecoder.Config.maxDecodeEmit]. * */ @JvmStatic @Throws(EncodingException::class) public fun CharSequence.decodeBuffered( - buf: ByteArray, decoder: Decoder<*>, + throwOnOverflow: Boolean, + buf: ByteArray, action: (buf: ByteArray, offset: Int, len: Int) -> Unit, ): Long = decoder.decodeBuffered( buf = buf, maxBufSize = buf.size, + throwOnOverflow = throwOnOverflow, _get = ::get, _input = { DecoderInput(this) }, _action = action, @@ -511,9 +534,10 @@ public sealed class Decoder(public val config: C) { * equal to the [DEFAULT_BUFFER_SIZE], then an array of that size will be allocated * and [action] is only invoked once (single-shot decoding). In the event that * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] throws its [EncodingSizeException] - * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]), or is greater - * than [DEFAULT_BUFFER_SIZE], then this function will always stream decode to a - * buffer while flushing to [action] until the decoding operation has completed. + * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]) while [throwOnOverflow] + * is `false`, or its return value is greater than [DEFAULT_BUFFER_SIZE], then this + * function will always stream decode to a buffer while flushing to [action] until + * the decoding operation has completed. * * **NOTE:** Documented exceptions thrown by this function do not include those * for which [action] may throw. @@ -527,6 +551,7 @@ public sealed class Decoder(public val config: C) { * val text = "Some long string" * val n = text.decodeBufferedAsync( * UTF8, + * false, * stream::writeAsync, * ) * println("Wrote $n UTF-8 bytes to file.txt") @@ -542,6 +567,9 @@ public sealed class Decoder(public val config: C) { * and [decodeBufferedAsync] APIs. * * @param [decoder] The [Decoder] to use. + * @param [throwOnOverflow] If `true` and [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * throws an [EncodingSizeException], it will be re-thrown. If `false`, the exception + * will be swallowed and stream decoding to the buffer will continue. * @param [action] The suspend function to flush the buffer to; a destination to * "write" decoded data to whereby `len` is the number of bytes within `buf`, * starting at index `offset`, to "write". @@ -555,13 +583,16 @@ public sealed class Decoder(public val config: C) { * @throws [CancellationException] * @throws [EncodingException] If decoding failed, such as the [decoder] rejecting * an invalid character or sequence. + * @throws [EncodingSizeException] If [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * threw its exception and [throwOnOverflow] is `true`. * */ @JvmStatic @Throws(CancellationException::class, EncodingException::class) public suspend inline fun CharSequence.decodeBufferedAsync( decoder: Decoder<*>, + throwOnOverflow: Boolean, noinline action: suspend (buf: ByteArray, offset: Int, len: Int) -> Unit, - ): Long = decodeBufferedAsync(DEFAULT_BUFFER_SIZE, decoder, action) + ): Long = decodeBufferedAsync(decoder, throwOnOverflow, DEFAULT_BUFFER_SIZE, action) /** * Decode a [CharSequence] using a maximum array size of [maxBufSize]. @@ -571,9 +602,10 @@ public sealed class Decoder(public val config: C) { * equal to the [maxBufSize], then an array of that size will be allocated * and [action] is only invoked once (single-shot decoding). In the event that * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] throws its [EncodingSizeException] - * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]), or is greater - * than [maxBufSize], then this function will always stream decode to a - * buffer while flushing to [action] until the decoding operation has completed. + * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]) while [throwOnOverflow] + * is `false`, or its return value is greater than [maxBufSize], then this + * function will always stream decode to a buffer while flushing to [action] until + * the decoding operation has completed. * * **NOTE:** Documented exceptions thrown by this function do not include those * for which [action] may throw. @@ -586,8 +618,9 @@ public sealed class Decoder(public val config: C) { * .useAsync { stream -> * val text = "Some long string" * val n = text.decodeBufferedAsync( - * 1024, * UTF8, + * false, + * 1024, * stream::writeAsync, * ) * println("Wrote $n UTF-8 bytes to file.txt") @@ -602,9 +635,12 @@ public sealed class Decoder(public val config: C) { * library that have not updated yet may fail when using them with [decodeBuffered] * and [decodeBufferedAsync] APIs. * + * @param [decoder] The [Decoder] to use. + * @param [throwOnOverflow] If `true` and [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * throws an [EncodingSizeException], it will be re-thrown. If `false`, the exception + * will be swallowed and stream decoding to the buffer will continue. * @param [maxBufSize] The maximum size array this function will allocate. Must * be greater than [EncoderDecoder.Config.maxDecodeEmit]. - * @param [decoder] The [Decoder] to use. * @param [action] The suspend function to flush the buffer to; a destination to * "write" decoded data to whereby `len` is the number of bytes within `buf`, * starting at index `offset`, to "write". @@ -618,18 +654,22 @@ public sealed class Decoder(public val config: C) { * @throws [CancellationException] * @throws [EncodingException] If decoding failed, such as the [decoder] rejecting * an invalid character or sequence. + * @throws [EncodingSizeException] If [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * threw its exception and [throwOnOverflow] is `true`. * @throws [IllegalArgumentException] If [maxBufSize] is less than or equal to * [EncoderDecoder.Config.maxDecodeEmit]. * */ @JvmStatic @Throws(CancellationException::class, EncodingException::class) public suspend fun CharSequence.decodeBufferedAsync( - maxBufSize: Int, decoder: Decoder<*>, + throwOnOverflow: Boolean, + maxBufSize: Int, action: suspend (buf: ByteArray, offset: Int, len: Int) -> Unit, ): Long = decoder.decodeBuffered( buf = null, maxBufSize = maxBufSize, + throwOnOverflow = throwOnOverflow, _get = ::get, _input = { DecoderInput(this) }, _action = { buf, offset, len -> action(buf, offset, len) }, @@ -642,9 +682,10 @@ public sealed class Decoder(public val config: C) { * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] is less than or equal to the [buf] * size, then [action] is only invoked once (single-shot decoding). In the event that * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] throws its [EncodingSizeException] - * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]), or is greater - * than [buf] size, then this function will always stream decode to [buf] while - * flushing to [action] until the decoding operation has completed. + * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]) while [throwOnOverflow] + * is `false`, or its return value is greater than [buf] size, then this + * function will always stream decode to a buffer while flushing to [action] until + * the decoding operation has completed. * * **NOTE:** Documented exceptions thrown by this function do not include those * for which [action] may throw. @@ -661,13 +702,15 @@ public sealed class Decoder(public val config: C) { * val text = "Some long string" * val buf = ByteArray(DEFAULT_BUFFER_SIZE) * var n = text.decodeBufferedAsync( - * buf, * UTF8, + * false, + * buf, * stream::writeAsync, * ) * n += text.decodeBufferedAsync( - * buf, * UTF8, + * false, + * buf, * stream::writeAsync, * ) * println("Wrote $n UTF-8 bytes to file.txt") @@ -682,9 +725,12 @@ public sealed class Decoder(public val config: C) { * library that have not updated yet may fail when using them with [decodeBuffered] * and [decodeBufferedAsync] APIs. * + * @param [decoder] The [Decoder] to use. + * @param [throwOnOverflow] If `true` and [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * throws an [EncodingSizeException], it will be re-thrown. If `false`, the exception + * will be swallowed and stream decoding to the buffer will continue. * @param [buf] The pre-allocated array to use as the buffer. Its size must be * greater than [EncoderDecoder.Config.maxDecodeEmit]. - * @param [decoder] The [Decoder] to use. * @param [action] The suspend function to flush the buffer to; a destination to * "write" decoded data to whereby `len` is the number of bytes within `buf`, * starting at index `offset`, to "write". @@ -698,18 +744,22 @@ public sealed class Decoder(public val config: C) { * @throws [CancellationException] * @throws [EncodingException] If decoding failed, such as the [decoder] rejecting * an invalid character or sequence. + * @throws [EncodingSizeException] If [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * threw its exception and [throwOnOverflow] is `true`. * @throws [IllegalArgumentException] If [buf] size is less than or equal to * [EncoderDecoder.Config.maxDecodeEmit]. * */ @JvmStatic @Throws(CancellationException::class, EncodingException::class) public suspend fun CharSequence.decodeBufferedAsync( - buf: ByteArray, decoder: Decoder<*>, + throwOnOverflow: Boolean, + buf: ByteArray, action: suspend (buf: ByteArray, offset: Int, len: Int) -> Unit, ): Long = decoder.decodeBuffered( buf = buf, maxBufSize = buf.size, + throwOnOverflow = throwOnOverflow, _get = ::get, _input = { DecoderInput(this) }, _action = { _buf, offset, len -> action(_buf, offset, len) }, @@ -723,9 +773,10 @@ public sealed class Decoder(public val config: C) { * equal to the [DEFAULT_BUFFER_SIZE], then an array of that size will be allocated * and [action] is only invoked once (single-shot decoding). In the event that * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] throws its [EncodingSizeException] - * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]), or is greater - * than [DEFAULT_BUFFER_SIZE], then this function will always stream decode to a - * buffer while flushing to [action] until the decoding operation has completed. + * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]) while [throwOnOverflow] + * is `false`, or its return value is greater than [DEFAULT_BUFFER_SIZE], then this + * function will always stream decode to a buffer while flushing to [action] until + * the decoding operation has completed. * * **NOTE:** Documented exceptions thrown by this function do not include those * for which [action] may throw. @@ -735,7 +786,7 @@ public sealed class Decoder(public val config: C) { * "/path/to/file.txt".toFile().openWrite(excl = null).use { stream -> * val n = "Some long string" * .toCharArray() - * .decodeBuffered(UTF8, stream::write) + * .decodeBuffered(UTF8, false, stream::write) * println("Wrote $n UTF-8 bytes to file.txt") * } * @@ -744,7 +795,7 @@ public sealed class Decoder(public val config: C) { * val d = SHA256() * "SGVsbG8gV29ybGQh" * .toCharArray() - * .decodeBuffered(Base64.Default, d::update) + * .decodeBuffered(Base64.Default, false, d::update) * // ... * * **NOTE:** The [Decoder] implementation must be compatible with version `2.6.0+` @@ -756,6 +807,9 @@ public sealed class Decoder(public val config: C) { * and [decodeBufferedAsync] APIs. * * @param [decoder] The [Decoder] to use. + * @param [throwOnOverflow] If `true` and [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * throws an [EncodingSizeException], it will be re-thrown. If `false`, the exception + * will be swallowed and stream decoding to the buffer will continue. * @param [action] The function to flush the buffer to; a destination to "write" * decoded data to whereby `len` is the number of bytes within `buf`, starting * at index `offset`, to "write". @@ -768,13 +822,16 @@ public sealed class Decoder(public val config: C) { * * @throws [EncodingException] If decoding failed, such as the [decoder] rejecting * an invalid character or sequence. + * @throws [EncodingSizeException] If [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * threw its exception and [throwOnOverflow] is `true`. * */ @JvmStatic @Throws(EncodingException::class) public inline fun CharArray.decodeBuffered( decoder: Decoder<*>, + throwOnOverflow: Boolean, noinline action: (buf: ByteArray, offset: Int, len: Int) -> Unit, - ): Long = decodeBuffered(DEFAULT_BUFFER_SIZE, decoder, action) + ): Long = decodeBuffered(decoder, throwOnOverflow, DEFAULT_BUFFER_SIZE, action) /** * Decode a [CharArray] using a maximum array size of [maxBufSize]. @@ -784,9 +841,10 @@ public sealed class Decoder(public val config: C) { * equal to the [maxBufSize], then an array of that size will be allocated * and [action] is only invoked once (single-shot decoding). In the event that * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] throws its [EncodingSizeException] - * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]), or is greater - * than [maxBufSize], then this function will always stream decode to a - * buffer while flushing to [action] until the decoding operation has completed. + * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]) while [throwOnOverflow] + * is `false`, or its return value is greater than [maxBufSize], then this + * function will always stream decode to a buffer while flushing to [action] until + * the decoding operation has completed. * * **NOTE:** Documented exceptions thrown by this function do not include those * for which [action] may throw. @@ -796,7 +854,7 @@ public sealed class Decoder(public val config: C) { * "/path/to/file.txt".toFile().openWrite(excl = null).use { stream -> * val n = "Some string" * .toCharArray() - * .decodeBuffered(1024, UTF8, stream::write) + * .decodeBuffered(UTF8, false, 1024, stream::write) * println("Wrote $n UTF-8 bytes to file.txt") * } * @@ -805,7 +863,7 @@ public sealed class Decoder(public val config: C) { * val d = SHA256() * "SGVsbG8gV29ybGQh" * .toCharArray() - * .decodeBuffered(1024, Base64.Default, d::update) + * .decodeBuffered(Base64.Default, false, 1024, d::update) * // ... * * **NOTE:** The [Decoder] implementation must be compatible with version `2.6.0+` @@ -816,9 +874,12 @@ public sealed class Decoder(public val config: C) { * library that have not updated yet may fail when using them with [decodeBuffered] * and [decodeBufferedAsync] APIs. * + * @param [decoder] The [Decoder] to use. + * @param [throwOnOverflow] If `true` and [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * throws an [EncodingSizeException], it will be re-thrown. If `false`, the exception + * will be swallowed and stream decoding to the buffer will continue. * @param [maxBufSize] The maximum size array this function will allocate. Must * be greater than [EncoderDecoder.Config.maxDecodeEmit]. - * @param [decoder] The [Decoder] to use. * @param [action] The function to flush the buffer to; a destination to "write" * decoded data to whereby `len` is the number of bytes within `buf`, starting * at index `offset`, to "write". @@ -831,18 +892,22 @@ public sealed class Decoder(public val config: C) { * * @throws [EncodingException] If decoding failed, such as the [decoder] rejecting * an invalid character or sequence. + * @throws [EncodingSizeException] If [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * threw its exception and [throwOnOverflow] is `true`. * @throws [IllegalArgumentException] If [maxBufSize] is less than or equal to * [EncoderDecoder.Config.maxDecodeEmit]. * */ @JvmStatic @Throws(EncodingException::class) public fun CharArray.decodeBuffered( - maxBufSize: Int, decoder: Decoder<*>, + throwOnOverflow: Boolean, + maxBufSize: Int, action: (buf: ByteArray, offset: Int, len: Int) -> Unit, ): Long = decoder.decodeBuffered( buf = null, maxBufSize = maxBufSize, + throwOnOverflow = throwOnOverflow, _get = ::get, _input = { DecoderInput(this) }, _action = action, @@ -855,9 +920,10 @@ public sealed class Decoder(public val config: C) { * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] is less than or equal to the [buf] * size, then [action] is only invoked once (single-shot decoding). In the event that * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] throws its [EncodingSizeException] - * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]), or is greater - * than [buf] size, then this function will always stream decode to [buf] while - * flushing to [action] until the decoding operation has completed. + * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]) while [throwOnOverflow] + * is `false`, or its return value is greater than [buf] size, then this + * function will always stream decode to a buffer while flushing to [action] until + * the decoding operation has completed. * * **NOTE:** Documented exceptions thrown by this function do not include those * for which [action] may throw. @@ -871,10 +937,10 @@ public sealed class Decoder(public val config: C) { * val buf = ByteArray(DEFAULT_BUFFER_SIZE) * var n = "Some string" * .toCharArray() - * .decodeBuffered(buf, UTF8, stream::write) + * .decodeBuffered(UTF8, false, buf, stream::write) * n += "Some other string" * .toCharArray() - * .decodeBuffered(buf, UTF8, stream::write) + * .decodeBuffered(UTF8, false, buf, stream::write) * println("Wrote $n UTF-8 bytes to file.txt") * } * @@ -884,10 +950,10 @@ public sealed class Decoder(public val config: C) { * val buf = ByteArray(DEFAULT_BUFFER_SIZE) * "SGVsbG8gV29ybGQh" * .toCharArray() - * .decodeBuffered(buf, Base64.Default, d::update) + * .decodeBuffered(Base64.Default, false, buf, d::update) * "SGVsbG8gV29ybGQh" * .toCharArray() - * .decodeBuffered(buf, Base64.Default, d::update) + * .decodeBuffered(Base64.Default, false, buf, d::update) * // ... * * **NOTE:** The [Decoder] implementation must be compatible with version `2.6.0+` @@ -898,9 +964,12 @@ public sealed class Decoder(public val config: C) { * library that have not updated yet may fail when using them with [decodeBuffered] * and [decodeBufferedAsync] APIs. * + * @param [decoder] The [Decoder] to use. + * @param [throwOnOverflow] If `true` and [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * throws an [EncodingSizeException], it will be re-thrown. If `false`, the exception + * will be swallowed and stream decoding to the buffer will continue. * @param [buf] The pre-allocated array to use as the buffer. Its size must be * greater than [EncoderDecoder.Config.maxDecodeEmit]. - * @param [decoder] The [Decoder] to use. * @param [action] The function to flush the buffer to; a destination to "write" * decoded data to whereby `len` is the number of bytes within `buf`, starting * at index `offset`, to "write". @@ -913,18 +982,22 @@ public sealed class Decoder(public val config: C) { * * @throws [EncodingException] If decoding failed, such as the [decoder] rejecting * an invalid character or sequence. + * @throws [EncodingSizeException] If [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * threw its exception and [throwOnOverflow] is `true`. * @throws [IllegalArgumentException] If [buf] size is less than or equal to * [EncoderDecoder.Config.maxDecodeEmit]. * */ @JvmStatic @Throws(EncodingException::class) public fun CharArray.decodeBuffered( - buf: ByteArray, decoder: Decoder<*>, + throwOnOverflow: Boolean, + buf: ByteArray, action: (buf: ByteArray, offset: Int, len: Int) -> Unit, ): Long = decoder.decodeBuffered( buf = buf, maxBufSize = buf.size, + throwOnOverflow = throwOnOverflow, _get = ::get, _input = { DecoderInput(this) }, _action = action, @@ -938,9 +1011,10 @@ public sealed class Decoder(public val config: C) { * equal to the [DEFAULT_BUFFER_SIZE], then an array of that size will be allocated * and [action] is only invoked once (single-shot decoding). In the event that * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] throws its [EncodingSizeException] - * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]), or is greater - * than [DEFAULT_BUFFER_SIZE], then this function will always stream decode to a - * buffer while flushing to [action] until the decoding operation has completed. + * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]) while [throwOnOverflow] + * is `false`, or its return value is greater than [DEFAULT_BUFFER_SIZE], then this + * function will always stream decode to a buffer while flushing to [action] until + * the decoding operation has completed. * * **NOTE:** Documented exceptions thrown by this function do not include those * for which [action] may throw. @@ -955,6 +1029,7 @@ public sealed class Decoder(public val config: C) { * .toCharArray() * val n = chars.decodeBufferedAsync( * UTF8, + * false, * stream::writeAsync, * ) * println("Wrote $n UTF-8 bytes to file.txt") @@ -970,6 +1045,9 @@ public sealed class Decoder(public val config: C) { * and [decodeBufferedAsync] APIs. * * @param [decoder] The [Decoder] to use. + * @param [throwOnOverflow] If `true` and [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * throws an [EncodingSizeException], it will be re-thrown. If `false`, the exception + * will be swallowed and stream decoding to the buffer will continue. * @param [action] The suspend function to flush the buffer to; a destination to * "write" decoded data to whereby `len` is the number of bytes within `buf`, * starting at index `offset`, to "write". @@ -983,13 +1061,16 @@ public sealed class Decoder(public val config: C) { * @throws [CancellationException] * @throws [EncodingException] If decoding failed, such as the [decoder] rejecting * an invalid character or sequence. + * @throws [EncodingSizeException] If [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * threw its exception and [throwOnOverflow] is `true`. * */ @JvmStatic @Throws(CancellationException::class, EncodingException::class) public suspend inline fun CharArray.decodeBufferedAsync( decoder: Decoder<*>, + throwOnOverflow: Boolean, noinline action: suspend (buf: ByteArray, offset: Int, len: Int) -> Unit, - ): Long = decodeBufferedAsync(DEFAULT_BUFFER_SIZE, decoder, action) + ): Long = decodeBufferedAsync(decoder, throwOnOverflow, DEFAULT_BUFFER_SIZE, action) /** * Decode a [CharArray] using a maximum array size of [maxBufSize]. @@ -999,9 +1080,10 @@ public sealed class Decoder(public val config: C) { * equal to the [maxBufSize], then an array of that size will be allocated * and [action] is only invoked once (single-shot decoding). In the event that * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] throws its [EncodingSizeException] - * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]), or is greater - * than [maxBufSize], then this function will always stream decode to a - * buffer while flushing to [action] until the decoding operation has completed. + * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]) while [throwOnOverflow] + * is `false`, or its return value is greater than [maxBufSize], then this + * function will always stream decode to a buffer while flushing to [action] until + * the decoding operation has completed. * * **NOTE:** Documented exceptions thrown by this function do not include those * for which [action] may throw. @@ -1015,8 +1097,9 @@ public sealed class Decoder(public val config: C) { * val chars = "Some long string" * .toCharArray() * val n = chars.decodeBufferedAsync( - * 1024, * UTF8, + * false, + * 1024, * stream::writeAsync, * ) * println("Wrote $n UTF-8 bytes to file.txt") @@ -1031,9 +1114,12 @@ public sealed class Decoder(public val config: C) { * library that have not updated yet may fail when using them with [decodeBuffered] * and [decodeBufferedAsync] APIs. * + * @param [decoder] The [Decoder] to use. + * @param [throwOnOverflow] If `true` and [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * throws an [EncodingSizeException], it will be re-thrown. If `false`, the exception + * will be swallowed and stream decoding to the buffer will continue. * @param [maxBufSize] The maximum size array this function will allocate. Must * be greater than [EncoderDecoder.Config.maxDecodeEmit]. - * @param [decoder] The [Decoder] to use. * @param [action] The suspend function to flush the buffer to; a destination to * "write" decoded data to whereby `len` is the number of bytes within `buf`, * starting at index `offset`, to "write". @@ -1047,18 +1133,22 @@ public sealed class Decoder(public val config: C) { * @throws [CancellationException] * @throws [EncodingException] If decoding failed, such as the [decoder] rejecting * an invalid character or sequence. + * @throws [EncodingSizeException] If [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * threw its exception and [throwOnOverflow] is `true`. * @throws [IllegalArgumentException] If [maxBufSize] is less than or equal to * [EncoderDecoder.Config.maxDecodeEmit]. * */ @JvmStatic @Throws(CancellationException::class, EncodingException::class) public suspend fun CharArray.decodeBufferedAsync( - maxBufSize: Int, decoder: Decoder<*>, + throwOnOverflow: Boolean, + maxBufSize: Int, action: suspend (buf: ByteArray, offset: Int, len: Int) -> Unit, ): Long = decoder.decodeBuffered( buf = null, maxBufSize = maxBufSize, + throwOnOverflow = throwOnOverflow, _get = ::get, _input = { DecoderInput(this) }, _action = { buf, offset, len -> action(buf, offset, len) }, @@ -1071,9 +1161,10 @@ public sealed class Decoder(public val config: C) { * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] is less than or equal to the [buf] * size, then [action] is only invoked once (single-shot decoding). In the event that * [EncoderDecoder.Config.decodeOutMaxSizeOrFail] throws its [EncodingSizeException] - * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]), or is greater - * than [buf] size, then this function will always stream decode to [buf] while - * flushing to [action] until the decoding operation has completed. + * due to an overflow (i.e. decoding would exceed [Int.MAX_VALUE]) while [throwOnOverflow] + * is `false`, or its return value is greater than [buf] size, then this + * function will always stream decode to a buffer while flushing to [action] until + * the decoding operation has completed. * * **NOTE:** Documented exceptions thrown by this function do not include those * for which [action] may throw. @@ -1091,13 +1182,15 @@ public sealed class Decoder(public val config: C) { * .toCharArray() * val buf = ByteArray(DEFAULT_BUFFER_SIZE) * var n = chars.decodeBufferedAsync( - * buf, * UTF8, + * false, + * buf, * stream::writeAsync, * ) * n += chars.decodeBufferedAsync( - * buf, * UTF8, + * false, + * buf, * stream::writeAsync, * ) * println("Wrote $n UTF-8 bytes to file.txt") @@ -1112,9 +1205,12 @@ public sealed class Decoder(public val config: C) { * library that have not updated yet may fail when using them with [decodeBuffered] * and [decodeBufferedAsync] APIs. * + * @param [decoder] The [Decoder] to use. + * @param [throwOnOverflow] If `true` and [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * throws an [EncodingSizeException], it will be re-thrown. If `false`, the exception + * will be swallowed and stream decoding to the buffer will continue. * @param [buf] The pre-allocated array to use as the buffer. Its size must be * greater than [EncoderDecoder.Config.maxDecodeEmit]. - * @param [decoder] The [Decoder] to use. * @param [action] The suspend function to flush the buffer to; a destination to * "write" decoded data to whereby `len` is the number of bytes within `buf`, * starting at index `offset`, to "write". @@ -1128,23 +1224,57 @@ public sealed class Decoder(public val config: C) { * @throws [CancellationException] * @throws [EncodingException] If decoding failed, such as the [decoder] rejecting * an invalid character or sequence. + * @throws [EncodingSizeException] If [EncoderDecoder.Config.decodeOutMaxSizeOrFail] + * threw its exception and [throwOnOverflow] is `true`. * @throws [IllegalArgumentException] If [buf] size is less than or equal to * [EncoderDecoder.Config.maxDecodeEmit]. * */ @JvmStatic @Throws(CancellationException::class, EncodingException::class) public suspend fun CharArray.decodeBufferedAsync( - buf: ByteArray, decoder: Decoder<*>, + throwOnOverflow: Boolean, + buf: ByteArray, action: suspend (buf: ByteArray, offset: Int, len: Int) -> Unit, ): Long = decoder.decodeBuffered( buf = buf, maxBufSize = buf.size, + throwOnOverflow = throwOnOverflow, _get = ::get, _input = { DecoderInput(this) }, _action = { _buf, offset, len -> action(_buf, offset, len) }, ) + /** + * TODO: Remove. See https://github.com/05nelsonm/encoding/issues/225 + * @suppress + * */ + @JvmStatic + @Throws(EncodingException::class) + @Deprecated( + message = "Will be removed upon 2.6.0 release", + replaceWith = ReplaceWith("decodeBuffered(decoder, false, action)") + ) + public inline fun CharSequence.decodeBuffered( + decoder: Decoder<*>, + noinline action: (buf: ByteArray, offset: Int, len: Int) -> Unit, + ): Long = decodeBuffered(decoder, false, DEFAULT_BUFFER_SIZE, action) + + /** + * TODO: Remove. See https://github.com/05nelsonm/encoding/issues/225 + * @suppress + * */ + @JvmStatic + @Throws(CancellationException::class, EncodingException::class) + @Deprecated( + message = "Will be removed upon 2.6.0 release", + replaceWith = ReplaceWith("decodeBufferedAsync(decoder, false, action)") + ) + public suspend inline fun CharSequence.decodeBufferedAsync( + decoder: Decoder<*>, + noinline action: suspend (buf: ByteArray, offset: Int, len: Int) -> Unit, + ): Long = decodeBufferedAsync(decoder, false, DEFAULT_BUFFER_SIZE, action) + /** * DEPRECATED since `2.3.0` * @throws [EncodingException] If decoding failed, such as the [decoder] rejecting diff --git a/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/EncoderDecoder.kt b/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/EncoderDecoder.kt index e0c4245..29dbd60 100644 --- a/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/EncoderDecoder.kt +++ b/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/EncoderDecoder.kt @@ -17,7 +17,6 @@ package io.matthewnelson.encoding.core -import io.matthewnelson.encoding.core.internal.calculatedOutputNegativeEncodingSizeException import io.matthewnelson.encoding.core.internal.closedException import io.matthewnelson.encoding.core.internal.isSpaceOrNewLine import io.matthewnelson.encoding.core.util.DecoderInput @@ -42,9 +41,9 @@ public abstract class EncoderDecoder(config: C): Encod public companion object { /** - * A "default" buffer size of `8 * 1024` + * A "default" buffer size of `8 * 1024`; it's a great value. * */ - public const val DEFAULT_BUFFER_SIZE: Int = 8 * 1024 // Note: If changing, update documentation. + public const val DEFAULT_BUFFER_SIZE: Int = 8 * 1024 } /** @@ -53,8 +52,8 @@ public abstract class EncoderDecoder(config: C): Encod public abstract class Config private constructor( /** - * If `true`, the characters ('\n', '\r', ' ', '\t') will be skipped over (i.e. - * allowed but ignored) during decoding operations. If `false`, a [MalformedEncodingException] + * If `true`, the characters ('\n', '\r', ' ', '\t') will be skipped over (i.e. allowed + * but ignored) during decoding operations. If `false`, a [MalformedEncodingException] * will be thrown when those characters are encountered. If `null`, those characters * are passed along to the [Decoder.Feed] implementation as input. * */ @@ -107,13 +106,13 @@ public abstract class EncoderDecoder(config: C): Encod * so its maximum emission is `1`. `Base32` decoding will emit `5` bytes for every `8` * characters of input, so its maximum emission is `5`. `UTF8` "decoding" (i.e. text to * UTF-8 byte transformations) can emit `4` bytes, but also depending on the size of the - * replacement byte sequence being used, can emit more; its maximum emission size is - * required to be calculated, such as `(replacementStrategy.size * 2).coerceAtLeast(4)`. + * replacement byte sequence being used, can emit more; its maximum emission size needs + * a calculation, such as `(replacementStrategy.size * 2).coerceAtLeast(4)`. * * Value will be between `1` and `255` (inclusive), or `-1` which indicates that the * [EncoderDecoder.Config] implementation has not updated to the new constructor introduced * in version `2.6.0`, and as such is unable to be used with `:core` module APIs dependent - * on this value (such as [Decoder.decodeBuffered] or [Decoder.decodeBufferedAsync]). + * on this value (such as [Decoder.decodeBuffered] and [Decoder.decodeBufferedAsync]). * */ @JvmField public val maxDecodeEmit: Int, @@ -126,8 +125,9 @@ public abstract class EncoderDecoder(config: C): Encod * For example, `Base16` encoding will emit `2` characters for every `1` byte of input, * so its maximum emission is `2`. `Base32` encoding will emit `8` characters for every * `5` bytes of input, so its maximum emission is `8`. `UTF8` "encoding" (i.e. UTF-8 byte - * to text transformations) can emit `4` characters for every `4` bytes of input (depending - * on the implementation), so its maximum emission would be `4`. + * to text transformations) can emit `2` characters, but also depending on the strategy + * being used for replacement sequences, can emit more; its maximum emission size needs + * some logic, such as `if (replacementStrategy == ReplacementStrategy.THROW) 2 else 4`. * * **NOTE:** This value does **not** take into consideration the [lineBreakInterval] setting, * or any other [LineBreakOutFeed]-like implementation that may inflate the maximum character @@ -239,7 +239,7 @@ public abstract class EncoderDecoder(config: C): Encod if (outSize < 0L) { // Long.MAX_VALUE was exceeded and encodeOutSizeProtected // did not implement checks to throw an exception. - throw calculatedOutputNegativeEncodingSizeException(outSize) + throw negativeEncodingSizeException(outSize) } if (lineBreakInterval > 0) { @@ -304,7 +304,7 @@ public abstract class EncoderDecoder(config: C): Encod if (outSize < 0L) { // Long.MAX_VALUE was exceeded and decodeOutMaxSizeProtected // did not implement checks to throw an exception. - throw calculatedOutputNegativeEncodingSizeException(outSize) + throw negativeEncodingSizeException(outSize) } return outSize } @@ -367,7 +367,7 @@ public abstract class EncoderDecoder(config: C): Encod if (outSize < 0) { // Long.MAX_VALUE was exceeded and decodeOutMaxSizeOrFailProtected // did not implement checks to throw an exception. - throw calculatedOutputNegativeEncodingSizeException(outSize) + throw negativeEncodingSizeException(outSize) } return outSize } @@ -805,3 +805,8 @@ private inline fun checkMaxEmitSize(size: Int, parameterName: () -> String) { throw IllegalArgumentException("$n must be less than 256") } } + +@Suppress("NOTHING_TO_INLINE") +internal inline fun negativeEncodingSizeException(outSize: Number): EncodingSizeException { + return EncodingSizeException("Calculated output of Size[$outSize] was negative") +} diff --git a/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-EncoderDecoder.kt b/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Decoder.kt similarity index 73% rename from library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-EncoderDecoder.kt rename to library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Decoder.kt index aa5942c..a95e2c1 100644 --- a/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-EncoderDecoder.kt +++ b/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Decoder.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -@file:Suppress("LocalVariableName", "NOTHING_TO_INLINE") +@file:Suppress("LocalVariableName") package io.matthewnelson.encoding.core.internal @@ -25,8 +25,6 @@ import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.math.min -private const val MAX_ENCODE_OUT_SIZE: Long = Int.MAX_VALUE.toLong() - @Throws(EncodingException::class) @OptIn(ExperimentalContracts::class) internal inline fun Decoder.decode( @@ -36,7 +34,8 @@ internal inline fun Decoder.decode( contract { callsInPlace(_get, InvocationKind.UNKNOWN) } val maxDecodeSize = config.decodeOutMaxSizeOrFail(input) val a = ByteArray(maxDecodeSize) - val len = decode(maxDecodeSizeArray = a, input.size, _get) + @Suppress("DEPRECATION") + val len = decodeTo(maxDecodeSizeArray = a, input.size, _get) if (len == maxDecodeSize) return a val copy = a.copyOf(len) if (config.backFillBuffers) { @@ -45,42 +44,12 @@ internal inline fun Decoder.decode( return copy } -@Throws(EncodingException::class) -@OptIn(ExperimentalContracts::class) -internal inline fun Decoder.decode( - maxDecodeSizeArray: ByteArray, - inputSize: Int, - _get: (i: Int) -> Char, -): Int { - contract { callsInPlace(_get, InvocationKind.UNKNOWN) } - if (inputSize == 0) return 0 - - var i = 0 - try { - newDecoderFeed(out = { b -> maxDecodeSizeArray[i++] = b }).use { feed -> - var j = 0 - while (j < inputSize) { - feed.consume(_get(j++)) - } - } - } catch (t: Throwable) { - if (config.backFillBuffers) { - maxDecodeSizeArray.fill(0, 0, min(maxDecodeSizeArray.size, i)) - } - if (t is IndexOutOfBoundsException && i >= maxDecodeSizeArray.size) { - // Something is wrong with the encoder's pre-calculation - throw EncodingSizeException("Encoder's pre-calculation of Size[${maxDecodeSizeArray.size}] was incorrect", t) - } - throw t - } - return i -} - @OptIn(ExperimentalContracts::class) @Throws(EncodingException::class, IllegalArgumentException::class) internal inline fun Decoder.decodeBuffered( buf: ByteArray?, maxBufSize: Int, + throwOnOverflow: Boolean, _get: (i: Int) -> Char, _input: () -> DecoderInput, _action: (buf: ByteArray, offset: Int, len: Int) -> Unit, @@ -108,18 +77,20 @@ internal inline fun Decoder.decodeBuffered( val input = _input() try { config.decodeOutMaxSizeOrFail(input) - } catch (_: EncodingSizeException) { - // Only ignore EncodingSizeException such that any checks - // the implementation has (such as Base32 Crockford) can - // fall through and end early. + } catch (e: EncodingSizeException) { + // Only ignore EncodingSizeException such that any checks the + // implementation has (such as Base32 Crockford check symbols) + // can fall through and end early. - -1 // output size exceeded Int.MAX_VALUE + if (throwOnOverflow) throw e + -1 }.let { maxDecodeSize -> if (maxDecodeSize !in 0..maxBufSize) return@let // Chunk // Maximum decoded size will be less than or equal to maxBufSize. One-shot it. val decoded = buf ?: ByteArray(maxDecodeSize) - val len = decode(maxDecodeSizeArray = decoded, input.size, _get) + @Suppress("DEPRECATION") + val len = decodeTo(maxDecodeSizeArray = decoded, input.size, _get) try { _action(decoded, 0, len) } finally { @@ -154,38 +125,34 @@ internal inline fun Decoder.decodeBuffered( return size } -/** - * Fails if the returned [Long] for [Config.encodeOutMaxSize] exceeds [Int.MAX_VALUE]. - * */ +@Throws(EncodingException::class) @OptIn(ExperimentalContracts::class) -@Throws(EncodingSizeException::class) -internal inline fun Encoder<*>.encodeOutMaxSizeOrFail( - size: Int, - _block: (maxSize: Int) -> T, -): T { - contract { callsInPlace(_block, InvocationKind.AT_MOST_ONCE) } +@Deprecated("UNSAFE; do not reference directly. Used by decode/decodeBuffered only.") +internal inline fun Decoder.decodeTo( + maxDecodeSizeArray: ByteArray, + inputSize: Int, + _get: (i: Int) -> Char, +): Int { + contract { callsInPlace(_get, InvocationKind.UNKNOWN) } + if (inputSize == 0) return 0 - val maxSize = config.encodeOutMaxSize(size.toLong()) - if (maxSize > MAX_ENCODE_OUT_SIZE) { - throw Config.outSizeExceedsMaxEncodingSizeException(maxSize, MAX_ENCODE_OUT_SIZE) + var i = 0 + try { + newDecoderFeed(out = { b -> maxDecodeSizeArray[i++] = b }).use { feed -> + var j = 0 + while (j < inputSize) { + feed.consume(_get(j++)) + } + } + } catch (t: Throwable) { + if (config.backFillBuffers) { + maxDecodeSizeArray.fill(0, 0, min(maxDecodeSizeArray.size, i)) + } + if (t is IndexOutOfBoundsException && i >= maxDecodeSizeArray.size) { + // Something is wrong with the encoder's pre-calculation + throw EncodingSizeException("Decoder's pre-calculation of Size[${maxDecodeSizeArray.size}] was incorrect", t) + } + throw t } - - return _block(maxSize.toInt()) -} - -internal inline fun Encoder.encode( - data: ByteArray, - out: Encoder.OutFeed, -) { - if (data.isEmpty()) return - newEncoderFeed(out).use { feed -> data.forEach { b -> feed.consume(b) } } -} - -internal inline fun EncoderDecoder.Feed<*>.closedException(): EncodingException { - return EncodingException("$this is closed") -} - -@Suppress("UnusedReceiverParameter") -internal inline fun Config.calculatedOutputNegativeEncodingSizeException(outSize: Number): EncodingSizeException { - return EncodingSizeException("Calculated output of Size[$outSize] was negative") + return i } diff --git a/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Encoder.kt b/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Encoder.kt new file mode 100644 index 0000000..f35ed0d --- /dev/null +++ b/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Encoder.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025 Matthew Nelson + * + * 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 + * + * https://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. + **/ +@file:Suppress("LocalVariableName", "NOTHING_TO_INLINE") + +package io.matthewnelson.encoding.core.internal + +import io.matthewnelson.encoding.core.Encoder +import io.matthewnelson.encoding.core.EncoderDecoder.Config +import io.matthewnelson.encoding.core.EncodingSizeException +import io.matthewnelson.encoding.core.use +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +private const val MAX_ENCODE_OUT_SIZE: Long = Int.MAX_VALUE.toLong() + +/** + * Fails if the returned [Long] for [Config.encodeOutMaxSize] exceeds [Int.MAX_VALUE]. + * */ +@OptIn(ExperimentalContracts::class) +@Throws(EncodingSizeException::class) +internal inline fun Encoder<*>.encodeOutMaxSizeOrFail( + size: Int, + _block: (maxSize: Int) -> T, +): T { + contract { callsInPlace(_block, InvocationKind.AT_MOST_ONCE) } + + val maxSize = config.encodeOutMaxSize(size.toLong()) + if (maxSize > MAX_ENCODE_OUT_SIZE) { + throw Config.outSizeExceedsMaxEncodingSizeException(maxSize, MAX_ENCODE_OUT_SIZE) + } + + return _block(maxSize.toInt()) +} + +internal inline fun Encoder.encode( + data: ByteArray, + out: Encoder.OutFeed, +) { + if (data.isEmpty()) return + newEncoderFeed(out).use { feed -> data.forEach { b -> feed.consume(b) } } +} diff --git a/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Helpers.kt b/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Util.kt similarity index 86% rename from library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Helpers.kt rename to library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Util.kt index 6511963..7bc0404 100644 --- a/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Helpers.kt +++ b/library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Util.kt @@ -17,6 +17,13 @@ package io.matthewnelson.encoding.core.internal +import io.matthewnelson.encoding.core.EncoderDecoder +import io.matthewnelson.encoding.core.EncodingException + +internal inline fun EncoderDecoder.Feed<*>.closedException(): EncodingException { + return EncodingException("$this is closed") +} + internal inline fun Char.isSpaceOrNewLine(): Boolean { return when(this) { '\n', '\r', ' ', '\t' -> true