Skip to content

Commit

Permalink
Add FileWrapper to handle file close on deallocation
Browse files Browse the repository at this point in the history
  • Loading branch information
valeriyvan committed Jun 1, 2024
1 parent 6cf7ff4 commit ebd11c3
Showing 1 changed file with 35 additions and 10 deletions.
45 changes: 35 additions & 10 deletions Sources/netpbm/PBMImageSequence.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
import Foundation

public class PBMImageSequence: AsyncSequence {
// Note about using UnsafeMutablePointer<FILE> instead of FileHandle.
//
// Would be nice to rewrite using FileHandle instead of UnsafeMutablePointer<FILE>.
// UnsafeMutablePointer<FILE> is plane C old API.
// FileHandle is from Objective-C era, but Swift friendly, could close file when FileHandle
// is deallocated, has API for async reading/writing.
// But FileHandle has API fragmented between different macOS versions for simple things
// like reading data from file.
// UnsafeMutablePointer<FILE> is settled API available everywhere.
// So it's questionable if FileHandle usage here is beneficial.

public struct PBMImageSequence: AsyncSequence {

// Closes file on deinit.
// Allows PBMImageSequence be struct and handle file close.
class FileWrapper {
let file: UnsafeMutablePointer<FILE>

init(file: UnsafeMutablePointer<FILE>) {
self.file = file
}

deinit {
if fclose(file) == EOF {
print("Error \(errno) closing file")
}
}
}

public typealias Element = PBMImageBitSequence
public typealias AsyncIterator = Iterator

Expand All @@ -18,28 +46,25 @@ public class PBMImageSequence: AsyncSequence {
}
}

public let file: UnsafeMutablePointer<FILE>
public var file: UnsafeMutablePointer<FILE> { fileWrapper.file }

let fileWrapper: FileWrapper

public init(string: String) throws {
file = try string.withCString {
let file = try string.withCString {
guard let file: UnsafeMutablePointer<FILE> = fmemopen(UnsafeMutableRawPointer(mutating: $0), strlen($0), "r") else {
throw NSError(domain: URLError.errorDomain, code: URLError.cannotOpenFile.rawValue)
}
return file
}
self.fileWrapper = FileWrapper(file: file)
}

public init(pathname: String) throws {
guard let file: UnsafeMutablePointer<FILE> = fopen(pathname, "r") else {
throw NSError(domain: URLError.errorDomain, code: URLError.cannotOpenFile.rawValue)
}
self.file = file
}

deinit {
if fclose(file) == EOF {
print("Error \(errno) closing file")
}
self.fileWrapper = FileWrapper(file: file)
}

public func makeAsyncIterator() -> Iterator {
Expand Down

0 comments on commit ebd11c3

Please sign in to comment.