refs #35 Buffer is not mutable, MutableBuffer added (to cache in serialized form)

This commit is contained in:
sergeych committed 2025-07-16 11:47:23 +03:00
1 parent f3d766d1b1
commit 7aee25ffef
6 files changed
+120 -44

No files matched your search

@@ -82,6 +82,11 @@ open class Scope(
}
}
fun requireNoArgs() {
if( args.list.isNotEmpty())
raiseError("This function does not accept any arguments")
}
inline fun <reified T : Obj> thisAs(): T = (thisObj as? T)
?: raiseClassCastError("Cannot cast ${thisObj.objClass.className} to ${T::class.simpleName}")
@@ -179,6 +179,7 @@ class Script(
ImportManager(rootScope, SecurityManager.allowAll).apply {
addPackage("lyng.buffer") {
it.addConst("Buffer", ObjBuffer.type)
it.addConst("MutableBuffer", ObjMutableBuffer.type)
}
addPackage("lyng.time") {
it.addConst("Instant", ObjInstant.type)
@@ -6,7 +6,7 @@ import net.sergeych.lyng.Scope
import net.sergeych.lyng.statement
import kotlin.math.min
class ObjBuffer(val byteArray: UByteArray) : Obj() {
open class ObjBuffer(val byteArray: UByteArray) : Obj() {
override val objClass: ObjClass = type
@@ -30,16 +30,6 @@ class ObjBuffer(val byteArray: UByteArray) : Obj() {
} else ObjInt(byteArray[checkIndex(scope, index)].toLong(), true)
}
override suspend fun putAt(scope: Scope, index: Obj, newValue: Obj) {
byteArray[checkIndex(scope, index.toObj())] = when (newValue) {
is ObjInt -> newValue.value.toUByte()
is ObjChar -> newValue.value.code.toUByte()
else -> scope.raiseIllegalArgument(
"invalid byte value for buffer at index ${index.inspect()}: ${newValue.inspect()}"
)
}
}
val size by byteArray::size
override fun hashCode(): Int {
@@ -144,18 +134,10 @@ class ObjBuffer(val byteArray: UByteArray) : Obj() {
thisAs<ObjBuffer>().byteArray.toByteArray().decodeToString()
)
}
// )
// addFn("getAt") {
// requireExactCount(1)
// thisAs<ObjList>().getAt(this, requiredArg<Obj>(0))
// }
// addFn("putAt") {
// requireExactCount(2)
// val newValue = args[1]
// thisAs<ObjList>().putAt(this, requiredArg<ObjInt>(0).value.toInt(), newValue)
// newValue
// }
addFn("toMutable") {
requireNoArgs()
ObjMutableBuffer(thisAs<ObjBuffer>().byteArray.copyOf())
}
}
}
}
@@ -0,0 +1,71 @@
package net.sergeych.lyng.obj
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.toList
import net.sergeych.lyng.Scope
class ObjMutableBuffer(byteArray: UByteArray) : ObjBuffer(byteArray) {
override suspend fun putAt(scope: Scope, index: Obj, newValue: Obj) {
byteArray[checkIndex(scope, index.toObj())] = when (newValue) {
is ObjInt -> newValue.value.toUByte()
is ObjChar -> newValue.value.code.toUByte()
else -> scope.raiseIllegalArgument(
"invalid byte value for buffer at index ${index.inspect()}: ${newValue.inspect()}"
)
}
}
companion object {
private suspend fun createBufferFrom(scope: Scope, obj: Obj): ObjBuffer =
when (obj) {
is ObjBuffer -> ObjMutableBuffer(obj.byteArray.copyOf())
is ObjInt -> {
if (obj.value < 0)
scope.raiseIllegalArgument("buffer size must be positive")
val data = UByteArray(obj.value.toInt())
ObjMutableBuffer(data)
}
is ObjString -> ObjMutableBuffer(obj.value.encodeToByteArray().asUByteArray())
else -> {
if (obj.isInstanceOf(ObjIterable)) {
ObjMutableBuffer(
obj.toFlow(scope).map { it.toLong().toUByte() }.toList().toTypedArray()
.toUByteArray()
)
} else
scope.raiseIllegalArgument(
"can't construct buffer from ${obj.inspect()}"
)
}
}
val type = object : ObjClass("MutableBuffer", ObjBuffer.type) {
override suspend fun callOn(scope: Scope): Obj {
val args = scope.args.list
return when (args.size) {
// empty buffer
0 -> ObjMutableBuffer(ubyteArrayOf())
1 -> createBufferFrom(scope, args[0])
else -> {
// create buffer from array, each argument should be a byte then:
val data = UByteArray(args.size)
for ((i, b) in args.withIndex()) {
val code = when (b) {
is ObjChar -> b.value.code.toUByte()
is ObjInt -> b.value.toUByte()
else -> scope.raiseIllegalArgument(
"invalid byte value for buffer constructor at index $i: ${b.inspect()}"
)
}
data[i] = code
}
ObjMutableBuffer(data)
}
}
}
}
}
}
+11 -3
View File
@@ -2477,12 +2477,14 @@ class ScriptTest {
assertEquals( 3, Buffer(1, 2, 3).size )
assertEquals( 5, Buffer("hello").size )
val buffer = Buffer("Hello")
var buffer = Buffer("Hello")
assertEquals( 5, buffer.size)
assertEquals('l'.code, buffer[2] )
assertEquals('l'.code, buffer[3] )
assertEquals("Hello", buffer.decodeUtf8())
buffer = buffer.toMutable()
buffer[2] = 101
assertEquals(101, buffer[2])
assertEquals("Heelo", buffer.decodeUtf8())
@@ -2503,6 +2505,12 @@ class ScriptTest {
val b3 = b1 + Buffer("!")
assertEquals( "Hello!", b3.decodeUtf8())
assert( b3 > b1 )
assert( b1 !== b2)
val map = Map( b1 => "foo")
assertEquals("foo", map[b1])
assertEquals("foo", map[b2])
assertEquals(null, map[b3])
""".trimIndent())
}
@@ -2615,7 +2623,7 @@ class ScriptTest {
import lyng.buffer
val b = Buffer(1,2,3)
val b = MutableBuffer(1,2,3)
b[1]++
assert( b == Buffer(1,3,3) )
++b[0]
@@ -2633,7 +2641,7 @@ class ScriptTest {
import lyng.buffer
val b = Buffer(1,2,3)
val b = Buffer(1,2,3).toMutable()
b[1]--
assert( b == Buffer(1,1,3) )
--b[0]