Fixed bugs found for the bitmap mask, JSON reader and wifi wrappers in the library.

This commit is contained in:
2026-09-18 12:50:47 +02:00
parent 9ae10590cc
commit d33cf4c528
5 changed files with 97 additions and 26 deletions
@@ -2,15 +2,18 @@ internal import CPlaydate
extension Graphics {
/// A drawable image and drawing target. Wraps `LCDBitmap`. Bitmaps borrowed from
/// tables, fonts, masks, video players, or the system live only as long as their owner.
/// tables, fonts, video players, or the system live only as long as their owner.
public final class Bitmap {
let pointer: OpaquePointer
/// Whether deinit frees the `LCDBitmap`.
let isOwned: Bool
/// Kept alive because this bitmap shares its pixels.
private let owner: Bitmap?
init(pointer: OpaquePointer, isOwned: Bool) {
init(pointer: OpaquePointer, isOwned: Bool, owner: Bitmap? = nil) {
self.pointer = pointer
self.isOwned = isOwned
self.owner = owner
}
public convenience init(width: Int, height: Int, backgroundColor: Color = .clear) {
@@ -126,10 +129,11 @@ extension Graphics {
gfx.pointee.setBitmapMask.unsafelyUnwrapped(pointer, mask?.pointer) != 0
}
/// Shares this bitmap's mask data: drawing into it edits the mask.
/// Shares this bitmap's mask data, and keeps this bitmap alive.
public var mask: Bitmap? {
// Owned by the caller; pixels are shared with `self`.
guard let mask = gfx.pointee.getBitmapMask.unsafelyUnwrapped(pointer) else { return nil }
return Bitmap(pointer: mask, isOwned: false)
return Bitmap(pointer: mask, isOwned: true, owner: self)
}
/// Whether opaque pixels of both bitmaps overlap within the non-empty `rect`.
+3 -3
View File
@@ -120,9 +120,9 @@ extension JSON {
// Borrowing keeps the `SDFile` open for the whole decode.
reader.userdata = file.pointer
reader.read = { userdata, buffer, size in
guard let userdata, let buffer else { return -1 }
let count = fileAPI.pointee.read.unsafelyUnwrapped(userdata, buffer, UInt32(size))
return count > 0 ? count : -1
// `file->read` returns 0 at end of data, as the decoder expects.
guard let userdata, let buffer else { return 0 }
return fileAPI.pointee.read.unsafelyUnwrapped(userdata, buffer, UInt32(size))
}
var outval = json_value()
let ok = withExtendedLifetime(context) {
+15 -10
View File
@@ -22,23 +22,28 @@ extension Network {
WifiStatus(rawValue: UInt32(networkAPI.pointee.getStatus.unsafelyUnwrapped().rawValue)) ?? .notConnected
}
/// `true` connects to the configured access point; `false` turns wifi off before
/// the 30 s idle timeout. `completion` (documented for `true` only) gets `nil`
/// on success; completions fire in call order.
public static func setEnabled(_ enabled: Bool, completion: ((NetError?) -> Void)? = nil) {
/// Connects to the access point now. `completion` gets `nil` on success, in call order.
public static func enable(completion: ((NetError?) -> Void)? = nil) {
if let completion {
setEnabledCompletions.append(completion)
networkAPI.pointee.setEnabled.unsafelyUnwrapped(enabled, { error in
guard !Network.setEnabledCompletions.isEmpty else { return }
let completion = Network.setEnabledCompletions.removeFirst()
enableCompletions.append(completion)
networkAPI.pointee.setEnabled.unsafelyUnwrapped(true, { error in
guard !Network.enableCompletions.isEmpty else { return }
let completion = Network.enableCompletions.removeFirst()
completion(Network.optionalError(error))
})
} else {
networkAPI.pointee.setEnabled.unsafelyUnwrapped(enabled, nil)
networkAPI.pointee.setEnabled.unsafelyUnwrapped(true, nil)
}
}
nonisolated(unsafe) private static var setEnabledCompletions: [(NetError?) -> Void] = []
/// Turns wifi off now, not after the 30 s idle timeout.
public static func disable() {
// No callback: C documents it for enabling only, and a queued one would take
// the next `enable` result.
networkAPI.pointee.setEnabled.unsafelyUnwrapped(false, nil)
}
nonisolated(unsafe) private static var enableCompletions: [(NetError?) -> Void] = []
/// Shared by HTTP and TCP. Retains `completion` until the C callback, which
/// fires only for `.ask`.