more Buffer encodings
This commit is contained in:
		
							parent
							
								
									2ac92a1d09
								
							
						
					
					
						commit
						eefecae7b4
					
				@ -102,20 +102,46 @@ As with [List], it is possible to use ranges as indexes to slice a Buffer:
 | 
			
		||||
 | 
			
		||||
    >>> void
 | 
			
		||||
 | 
			
		||||
## Encoding
 | 
			
		||||
 | 
			
		||||
You can encode `String` to buffer using buffer constructor, as was shown. Also, buffer supports out of the box base64 (
 | 
			
		||||
which is used in `toString`) and hex encoding:
 | 
			
		||||
 | 
			
		||||
    import lyng.buffer
 | 
			
		||||
    
 | 
			
		||||
    // to UTF8 and back:
 | 
			
		||||
    val b = Buffer("hello")
 | 
			
		||||
    assertEquals( "hello", b.decodeUtf8() )
 | 
			
		||||
    
 | 
			
		||||
    // to base64 and back:
 | 
			
		||||
    assertEquals( b, Buffer.decodeBase64(b.base64) )
 | 
			
		||||
    assertEquals( b, Buffer.decodeHex(b.hex) )
 | 
			
		||||
    >>> void
 | 
			
		||||
 | 
			
		||||
## Members
 | 
			
		||||
 | 
			
		||||
| name          | meaning                            | type          |
 | 
			
		||||
|---------------|------------------------------------|---------------|
 | 
			
		||||
| `size`        | size                               | Int           |
 | 
			
		||||
| `decodeUtf8`  | decodee to String using UTF8 rules | Any           |
 | 
			
		||||
| `+`           | buffer concatenation               | Any           |
 | 
			
		||||
| `toMutable()` | create a mutable copy              | MutableBuffer |
 | 
			
		||||
| name                      | meaning                           | type          |
 | 
			
		||||
|---------------------------|-----------------------------------|---------------|
 | 
			
		||||
| `size`                    | size                              | Int           |
 | 
			
		||||
| `decodeUtf8`              | decode to String using UTF8 rules | Any           |
 | 
			
		||||
| `+`                       | buffer concatenation              | Any           |
 | 
			
		||||
| `toMutable()`             | create a mutable copy             | MutableBuffer |
 | 
			
		||||
| `hex`                     | encode to hex strign              | String        |
 | 
			
		||||
| `Buffer.decodeHex(hexStr) | decode hex string                 | Buffer        |
 | 
			
		||||
| `base64`                  | encode to base64 (url flavor) (2) | String        |
 | 
			
		||||
| `Buffer.decodeBase64`     | decode base64 to new Buffer (2)   | Buffer        |
 | 
			
		||||
 | 
			
		||||
(1)
 | 
			
		||||
: optimized implementation that override `Iterable` one
 | 
			
		||||
 | 
			
		||||
(2)
 | 
			
		||||
: base64url alphabet is used without trailing '=', which allows string to be used in URI without escaping. Note that
 | 
			
		||||
decoding supports both traditional and URL alphabets automatically, and ignores filling `=` characters. Base64URL is
 | 
			
		||||
well known and mentioned in the internet, for example, [here](https://base64.guru/standards/base64url).
 | 
			
		||||
 | 
			
		||||
Also, it inherits methods from [Iterable] and [Array].
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[Range]: Range.md
 | 
			
		||||
 | 
			
		||||
[Iterable]: Iterable.md
 | 
			
		||||
@ -21,7 +21,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
 | 
			
		||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
 | 
			
		||||
 | 
			
		||||
group = "net.sergeych"
 | 
			
		||||
version = "0.8.11-SNAPSHOT"
 | 
			
		||||
version = "0.8.12-SNAPSHOT"
 | 
			
		||||
 | 
			
		||||
buildscript {
 | 
			
		||||
    repositories {
 | 
			
		||||
 | 
			
		||||
@ -288,6 +288,9 @@ open class Obj {
 | 
			
		||||
            addFn("toString") {
 | 
			
		||||
                thisObj.asStr
 | 
			
		||||
            }
 | 
			
		||||
            addFn("inspect", true) {
 | 
			
		||||
                thisObj.inspect().toObj()
 | 
			
		||||
            }
 | 
			
		||||
            addFn("contains") {
 | 
			
		||||
                ObjBool(thisObj.contains(this, args.firstAndOnly()))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ package net.sergeych.lyng.obj
 | 
			
		||||
 | 
			
		||||
import kotlinx.coroutines.flow.map
 | 
			
		||||
import kotlinx.coroutines.flow.toList
 | 
			
		||||
import net.sergeych.bintools.decodeHex
 | 
			
		||||
import net.sergeych.bintools.encodeToHex
 | 
			
		||||
import net.sergeych.bintools.toDump
 | 
			
		||||
import net.sergeych.lyng.Scope
 | 
			
		||||
@ -26,12 +27,17 @@ import net.sergeych.lyng.statement
 | 
			
		||||
import net.sergeych.lynon.LynonDecoder
 | 
			
		||||
import net.sergeych.lynon.LynonEncoder
 | 
			
		||||
import net.sergeych.lynon.LynonType
 | 
			
		||||
import net.sergeych.mp_tools.decodeBase64Url
 | 
			
		||||
import net.sergeych.mp_tools.encodeToBase64Url
 | 
			
		||||
import kotlin.math.min
 | 
			
		||||
 | 
			
		||||
open class ObjBuffer(val byteArray: UByteArray) : Obj() {
 | 
			
		||||
 | 
			
		||||
    override val objClass: ObjClass = type
 | 
			
		||||
 | 
			
		||||
    val hex by lazy { byteArray.encodeToHex("")}
 | 
			
		||||
    val base64 by lazy { byteArray.toByteArray().encodeToBase64Url()}
 | 
			
		||||
 | 
			
		||||
    fun checkIndex(scope: Scope, index: Obj): Int {
 | 
			
		||||
        if (index !is ObjInt)
 | 
			
		||||
            scope.raiseIllegalArgument("index must be Int")
 | 
			
		||||
@ -83,9 +89,7 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
 | 
			
		||||
        } else scope.raiseIllegalArgument("can't concatenate buffer with ${other.inspect()}")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun toString(): String {
 | 
			
		||||
        return "Buffer(${byteArray.encodeToHex()})"
 | 
			
		||||
    }
 | 
			
		||||
    override fun toString(): String = base64
 | 
			
		||||
 | 
			
		||||
    override fun equals(other: Any?): Boolean {
 | 
			
		||||
        if (this === other) return true
 | 
			
		||||
@ -102,6 +106,8 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
 | 
			
		||||
        encoder.encodeCachedBytes(byteArray.asByteArray())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun inspect(): String = "Buf($base64)"
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        private suspend fun createBufferFrom(scope: Scope, obj: Obj): ObjBuffer =
 | 
			
		||||
            when (obj) {
 | 
			
		||||
@ -158,11 +164,27 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
 | 
			
		||||
                })
 | 
			
		||||
 | 
			
		||||
        }.apply {
 | 
			
		||||
            addClassFn("decodeBase64") {
 | 
			
		||||
                ObjBuffer(requireOnlyArg<Obj>().toString().decodeBase64Url().asUByteArray())
 | 
			
		||||
            }
 | 
			
		||||
            addClassFn("decodeHex") {
 | 
			
		||||
                ObjBuffer(requireOnlyArg<Obj>().toString().decodeHex().asUByteArray())
 | 
			
		||||
            }
 | 
			
		||||
            createField("size",
 | 
			
		||||
                statement {
 | 
			
		||||
                    (thisObj as ObjBuffer).byteArray.size.toObj()
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
            createField("hex",
 | 
			
		||||
                statement {
 | 
			
		||||
                    thisAs<ObjBuffer>().hex.toObj()
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
            createField("base64",
 | 
			
		||||
                statement {
 | 
			
		||||
                    thisAs<ObjBuffer>().base64.toObj()
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
            addFn("decodeUtf8") {
 | 
			
		||||
                ObjString(
 | 
			
		||||
                    thisAs<ObjBuffer>().byteArray.toByteArray().decodeToString()
 | 
			
		||||
 | 
			
		||||
@ -95,10 +95,8 @@ fun Iterable.joinToString(prefix=" ", transformer=null) {
 | 
			
		||||
 | 
			
		||||
fun Iterable.any(predicate): Bool {
 | 
			
		||||
    for( i in this ) {
 | 
			
		||||
        if( predicate(i) ) {
 | 
			
		||||
        break true
 | 
			
		||||
        // todo: add cancelIteration() in for loop!
 | 
			
		||||
        }
 | 
			
		||||
        if( predicate(i) )
 | 
			
		||||
            break true
 | 
			
		||||
    } else false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2630,6 +2630,26 @@ class ScriptTest {
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testBufferEncodings() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
            import lyng.buffer
 | 
			
		||||
            
 | 
			
		||||
            val b = Buffer("hello")
 | 
			
		||||
            println(b.toDump())
 | 
			
		||||
            assertEquals( "hello", b.decodeUtf8() )
 | 
			
		||||
            
 | 
			
		||||
            println(b.base64)
 | 
			
		||||
            println(b.hex)
 | 
			
		||||
 | 
			
		||||
            assertEquals( b, Buffer.decodeBase64(b.base64) )
 | 
			
		||||
            assertEquals( b, Buffer.decodeHex(b.hex) )
 | 
			
		||||
            
 | 
			
		||||
            println(b.inspect())
 | 
			
		||||
                        
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testBufferCompare() = runTest {
 | 
			
		||||
        eval(
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user