Swift bindings to the Playdate C API

Wraps all ten subsystems of the Playdate SDK 3.1.1 C API (system, display,
graphics, sprites, sound, file, JSON, Lua, scoreboards, network) in
idiomatic Swift: namespaced APIs, wrapper types with ownership semantics,
closures for callbacks, and typed throws. Written within the Embedded Swift
subset so the same code can target the device.

The SDK headers are resolved through a "playdate" pkg-config module
(Scripts/install-pkgconfig.sh), so the package works as a normal SwiftPM
dependency without unsafe build flags.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 10:33:45 +02:00
co-authored by Claude Fable 5
commit 09760f99b0
29 changed files with 6533 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
//
// Support.swift
// Internal helpers shared by the wrappers.
//
// C-string conversions are implemented manually (rather than with
// `String(cString:)` / `withCString`) so the module stays within the
// Embedded Swift subset used for device builds.
//
internal import CPlaydate
extension String {
/// Creates a string by copying a null-terminated UTF-8 C string.
init(playdateCString pointer: UnsafePointer<CChar>) {
var count = 0
while pointer[count] != 0 { count += 1 }
let bytes = UnsafeRawBufferPointer(start: pointer, count: count)
self = String(decoding: bytes, as: UTF8.self)
}
/// Creates a string from a nullable C string, or `nil` if the pointer is null.
init?(playdateCString pointer: UnsafePointer<CChar>?) {
guard let pointer else { return nil }
self.init(playdateCString: pointer)
}
/// Calls `body` with a temporary null-terminated UTF-8 copy of the string.
func withPlaydateCString<Result>(_ body: (UnsafePointer<CChar>) -> Result) -> Result {
var utf8 = ContiguousArray(self.utf8)
utf8.append(0)
return utf8.withUnsafeBufferPointer { buffer in
buffer.withMemoryRebound(to: CChar.self) { rebound in
body(rebound.baseAddress.unsafelyUnwrapped)
}
}
}
/// Copies the string into a newly allocated null-terminated C string.
/// The caller owns the memory and must free it with `deallocate()`.
func copiedPlaydateCString() -> UnsafeMutablePointer<CChar> {
let utf8 = ContiguousArray(self.utf8)
let buffer = UnsafeMutablePointer<CChar>.allocate(capacity: utf8.count + 1)
for (index, byte) in utf8.enumerated() {
buffer[index] = CChar(bitPattern: byte)
}
buffer[utf8.count] = 0
return buffer
}
}