blob: b67435bd1ae6f867810b79d96a08e9f4d3827066 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
public object FfiConverterString: FfiConverter<String, RustBuffer.ByValue> {
// Note: we don't inherit from FfiConverterRustBuffer, because we use a
// special encoding when lowering/lifting. We can use `RustBuffer.len` to
// store our length and avoid writing it out to the buffer.
override fun lift(value: RustBuffer.ByValue): String {
try {
val byteArr = ByteArray(value.len.toInt())
value.asByteBuffer()!!.get(byteArr)
return byteArr.toString(Charsets.UTF_8)
} finally {
RustBuffer.free(value)
}
}
override fun read(buf: ByteBuffer): String {
val len = buf.getInt()
val byteArr = ByteArray(len)
buf.get(byteArr)
return byteArr.toString(Charsets.UTF_8)
}
fun toUtf8(value: String): ByteBuffer {
// Make sure we don't have invalid UTF-16, check for lone surrogates.
return Charsets.UTF_8.newEncoder().run {
onMalformedInput(CodingErrorAction.REPORT)
encode(CharBuffer.wrap(value))
}
}
override fun lower(value: String): RustBuffer.ByValue {
val byteBuf = toUtf8(value)
// Ideally we'd pass these bytes to `ffi_bytebuffer_from_bytes`, but doing so would require us
// to copy them into a JNA `Memory`. So we might as well directly copy them into a `RustBuffer`.
val rbuf = RustBuffer.alloc(byteBuf.limit().toULong())
rbuf.asByteBuffer()!!.put(byteBuf)
return rbuf
}
// We aren't sure exactly how many bytes our string will be once it's UTF-8
// encoded. Allocate 3 bytes per UTF-16 code unit which will always be
// enough.
override fun allocationSize(value: String): ULong {
val sizeForLength = 4UL
val sizeForString = value.length.toULong() * 3UL
return sizeForLength + sizeForString
}
override fun write(value: String, buf: ByteBuffer) {
val byteBuf = toUtf8(value)
buf.putInt(byteBuf.limit())
buf.put(byteBuf)
}
}
|