|
| 1 | +package com.flipcash.shared |
| 2 | + |
| 3 | +import kotlinx.cinterop.BetaInteropApi |
| 4 | +import kotlinx.cinterop.ExperimentalForeignApi |
| 5 | +import kotlinx.cinterop.addressOf |
| 6 | +import kotlinx.cinterop.usePinned |
| 7 | +import platform.Foundation.NSData |
| 8 | +import platform.Foundation.create |
| 9 | +import platform.posix.memcpy |
| 10 | + |
| 11 | +/** |
| 12 | + * Bulk conversions between Foundation's `NSData` and Kotlin's `ByteArray`. |
| 13 | + * |
| 14 | + * Swift callers have no other way to hand a `ByteArray` its contents than `set(index:value:)`, |
| 15 | + * which is one Objective-C message send per byte. Copying through `NSData` instead moves the |
| 16 | + * whole buffer in a single `memcpy`, which matters for anything larger than a key or a hash — |
| 17 | + * the discrete-curve tables are 6.7 MB. |
| 18 | + */ |
| 19 | +@OptIn(ExperimentalForeignApi::class, BetaInteropApi::class) |
| 20 | +object SharedBytes { |
| 21 | + |
| 22 | + /** Copies [data]'s bytes into a new `ByteArray`. */ |
| 23 | + fun byteArray(data: NSData): ByteArray { |
| 24 | + val size = data.length.toInt() |
| 25 | + if (size == 0) return ByteArray(0) |
| 26 | + val bytes = ByteArray(size) |
| 27 | + bytes.usePinned { memcpy(it.addressOf(0), data.bytes, data.length) } |
| 28 | + return bytes |
| 29 | + } |
| 30 | + |
| 31 | + /** Copies [bytes] into a new `NSData`. */ |
| 32 | + fun data(bytes: ByteArray): NSData { |
| 33 | + if (bytes.isEmpty()) return NSData() |
| 34 | + return bytes.usePinned { |
| 35 | + NSData.create(bytes = it.addressOf(0), length = bytes.size.toULong()) |
| 36 | + } |
| 37 | + } |
| 38 | +} |
0 commit comments