Promote subsystem namespaces to the top level of the module

System, Display, Graphics, Sprite, Sound, File, JSON, Lua, Scoreboards,
Network, Rect, SystemEvent, and AccessReply now live at module scope
instead of being nested in the Playdate enum; consumers write
System.log(...) instead of Playdate.System.log(...), and can qualify with
the module name (PlayDate.System) on collision. The Playdate enum remains
only as the raw C API bootstrap (initialize(with:), api, apiPointer), and
Playdate.Error is renamed PlaydateError so no top-level type shadows
Swift.Error.

Breaking change for any existing consumers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 11:10:25 +02:00
co-authored by Claude Fable 5
parent 3ee071e098
commit 6485997edc
22 changed files with 801 additions and 822 deletions
+22 -24
View File
@@ -11,16 +11,14 @@ internal import CPlaydate
private var fileAPI: playdate_file { Playdate.api.file.pointee }
/// The most recent file system error as a thrown error.
private func lastFileError() -> Playdate.Error {
Playdate.Error(cString: fileAPI.geterr.unsafelyUnwrapped())
private func lastFileError() -> PlaydateError {
PlaydateError(cString: fileAPI.geterr.unsafelyUnwrapped())
}
extension Playdate {
/// The file API: access to the game's Data directory and pdx contents.
public enum File {}
}
/// The file API: access to the game's Data directory and pdx contents.
public enum File {}
extension Playdate.File {
extension File {
// MARK: - Types
/// How to open a file.
@@ -44,7 +42,7 @@ extension Playdate.File {
public struct Stat: Sendable {
public let isDirectory: Bool
public let size: UInt32
public let modified: Playdate.System.DateTime
public let modified: System.DateTime
}
/// The origin used by `Handle.seek(to:from:)`.
@@ -59,7 +57,7 @@ extension Playdate.File {
/// Calls `each` with the name of every file in `path`. Subdirectory names
/// end in a slash. Throws if the directory does not exist.
public static func listFiles(at path: String, showHidden: Bool = false,
_ each: (String) -> Void) throws(Playdate.Error) {
_ each: (String) -> Void) throws(PlaydateError) {
let result = withoutActuallyEscaping(each) { each in
var callback = each
return path.withPlaydateCString { cPath in
@@ -76,27 +74,27 @@ extension Playdate.File {
}
/// Information about the file or directory at `path`.
public static func stat(_ path: String) throws(Playdate.Error) -> Stat {
public static func stat(_ path: String) throws(PlaydateError) -> Stat {
var stat = FileStat()
let result = path.withPlaydateCString { fileAPI.stat.unsafelyUnwrapped($0, &stat) }
if result != 0 { throw lastFileError() }
return Stat(
isDirectory: stat.isdir != 0,
size: stat.size,
modified: Playdate.System.DateTime(
modified: System.DateTime(
year: UInt16(stat.m_year), month: UInt8(stat.m_month), day: UInt8(stat.m_day),
hour: UInt8(stat.m_hour), minute: UInt8(stat.m_minute), second: UInt8(stat.m_second)))
}
/// Creates a directory (and intermediate directories) in the Data directory.
public static func mkdir(_ path: String) throws(Playdate.Error) {
public static func mkdir(_ path: String) throws(PlaydateError) {
let result = path.withPlaydateCString { fileAPI.mkdir.unsafelyUnwrapped($0) }
if result != 0 { throw lastFileError() }
}
/// Deletes the file or directory at `path`. Directories require
/// `recursive` to be deleted with their contents.
public static func unlink(_ path: String, recursive: Bool = false) throws(Playdate.Error) {
public static func unlink(_ path: String, recursive: Bool = false) throws(PlaydateError) {
let result = path.withPlaydateCString {
fileAPI.unlink.unsafelyUnwrapped($0, recursive ? 1 : 0)
}
@@ -105,7 +103,7 @@ extension Playdate.File {
/// Renames (moves) a file in the Data directory, overwriting any existing
/// file at the destination.
public static func rename(from: String, to: String) throws(Playdate.Error) {
public static func rename(from: String, to: String) throws(PlaydateError) {
let result = from.withPlaydateCString { cFrom in
to.withPlaydateCString { cTo in
fileAPI.rename.unsafelyUnwrapped(cFrom, cTo)
@@ -123,7 +121,7 @@ extension Playdate.File {
private var isClosed = false
/// Opens the file at `path`.
public init(path: String, mode: Options) throws(Playdate.Error) {
public init(path: String, mode: Options) throws(PlaydateError) {
let pointer = path.withPlaydateCString {
fileAPI.open.unsafelyUnwrapped($0, mode.cValue)
}
@@ -138,7 +136,7 @@ extension Playdate.File {
}
/// Closes the file. Further operations are invalid.
public func close() throws(Playdate.Error) {
public func close() throws(PlaydateError) {
guard !isClosed else { return }
isClosed = true
if fileAPI.close.unsafelyUnwrapped(pointer) != 0 { throw lastFileError() }
@@ -146,7 +144,7 @@ extension Playdate.File {
/// Reads up to `buffer.count` bytes into `buffer`. Returns the number
/// of bytes read; 0 indicates end of file.
public func read(into buffer: UnsafeMutableRawBufferPointer) throws(Playdate.Error) -> Int {
public func read(into buffer: UnsafeMutableRawBufferPointer) throws(PlaydateError) -> Int {
let result = fileAPI.read.unsafelyUnwrapped(
pointer, buffer.baseAddress, UInt32(buffer.count))
if result < 0 { throw lastFileError() }
@@ -154,7 +152,7 @@ extension Playdate.File {
}
/// Reads up to `length` bytes and returns them.
public func read(length: Int) throws(Playdate.Error) -> [UInt8] {
public func read(length: Int) throws(PlaydateError) -> [UInt8] {
var bytes = [UInt8](repeating: 0, count: length)
let result = bytes.withUnsafeMutableBytes { buffer in
fileAPI.read.unsafelyUnwrapped(pointer, buffer.baseAddress, UInt32(buffer.count))
@@ -166,7 +164,7 @@ extension Playdate.File {
/// Writes the buffer to the file. Returns the number of bytes written.
@discardableResult
public func write(_ buffer: UnsafeRawBufferPointer) throws(Playdate.Error) -> Int {
public func write(_ buffer: UnsafeRawBufferPointer) throws(PlaydateError) -> Int {
let result = fileAPI.write.unsafelyUnwrapped(
pointer, buffer.baseAddress, UInt32(buffer.count))
if result < 0 { throw lastFileError() }
@@ -175,7 +173,7 @@ extension Playdate.File {
/// Writes the bytes to the file. Returns the number of bytes written.
@discardableResult
public func write(_ bytes: [UInt8]) throws(Playdate.Error) -> Int {
public func write(_ bytes: [UInt8]) throws(PlaydateError) -> Int {
let result = bytes.withUnsafeBytes { buffer in
fileAPI.write.unsafelyUnwrapped(pointer, buffer.baseAddress, UInt32(buffer.count))
}
@@ -185,27 +183,27 @@ extension Playdate.File {
/// Writes the string's UTF-8 to the file. Returns the bytes written.
@discardableResult
public func write(_ string: String) throws(Playdate.Error) -> Int {
public func write(_ string: String) throws(PlaydateError) -> Int {
try write(Array(string.utf8))
}
/// Flushes buffered writes to disk. Returns the bytes written.
@discardableResult
public func flush() throws(Playdate.Error) -> Int {
public func flush() throws(PlaydateError) -> Int {
let result = fileAPI.flush.unsafelyUnwrapped(pointer)
if result < 0 { throw lastFileError() }
return Int(result)
}
/// The current read/write offset.
public func tell() throws(Playdate.Error) -> Int {
public func tell() throws(PlaydateError) -> Int {
let result = fileAPI.tell.unsafelyUnwrapped(pointer)
if result < 0 { throw lastFileError() }
return Int(result)
}
/// Moves the read/write offset to `offset` relative to `origin`.
public func seek(to offset: Int, from origin: SeekOrigin = .start) throws(Playdate.Error) {
public func seek(to offset: Int, from origin: SeekOrigin = .start) throws(PlaydateError) {
if fileAPI.seek.unsafelyUnwrapped(pointer, Int32(offset), origin.rawValue) != 0 {
throw lastFileError()
}