From c68e980d8462f36a91e693d1273c3065c1355acb Mon Sep 17 00:00:00 2001 From: George Barnett Date: Tue, 23 Jan 2024 16:10:07 +0000 Subject: [PATCH 1/4] Make Zlib.Compressor/Decompressor classes Motivation: z_stream stores a pointer to itself in its internal state which it checks against in inflate/deflate. As we hold these within structs, and call through to C functions which take a pointer to a z_stream, this address can change as the struct is copied about. This results in errors when calling deflate/inflate. Modifications: - Make Compressor/Decompressor classes - Move the initialize call to init and the end call to deinit. Result: Harder to misue compressor/decompressor --- Sources/GRPCHTTP2Core/Compression/Zlib.swift | 51 ++++++++----------- .../Server/Compression/ZlibTests.swift | 22 ++------ 2 files changed, 26 insertions(+), 47 deletions(-) diff --git a/Sources/GRPCHTTP2Core/Compression/Zlib.swift b/Sources/GRPCHTTP2Core/Compression/Zlib.swift index f8abeff98..dd513dd0d 100644 --- a/Sources/GRPCHTTP2Core/Compression/Zlib.swift +++ b/Sources/GRPCHTTP2Core/Compression/Zlib.swift @@ -37,29 +37,24 @@ enum Zlib { extension Zlib { /// Creates a new compressor for the given compression format. /// - /// This compressor is only suitable for compressing whole messages at a time. Callers - /// must ``initialize()`` the compressor before using it. - struct Compressor { + /// This compressor is only suitable for compressing whole messages at a time. + final class Compressor { + // Note: the compressor and decompressor are classes. This is intentional as a z_stream stores + // a pointer back to itself within its internal state. Calls to deflate and inflate do a state + // check ensuring that the stream pointer and its pointer-to-self held by its internal state + // are the same. However, within a struct held on the stack this location can change and results + // in errors in deflate/inflate. private var stream: z_stream private let method: Method - private var isInitialized = false init(method: Method) { self.method = method self.stream = z_stream() - } - - /// Initialize the compressor. - mutating func initialize() { - precondition(!self.isInitialized) self.stream.deflateInit(windowBits: self.method.windowBits) - self.isInitialized = true } - static func initialized(_ method: Method) -> Self { - var compressor = Compressor(method: method) - compressor.initialize() - return compressor + deinit { + self.end() } /// Compresses the data in `input` into the `output` buffer. @@ -68,15 +63,14 @@ extension Zlib { /// - Parameter output: The `ByteBuffer` into which the compressed message should be written. /// - Returns: The number of bytes written into the `output` buffer. @discardableResult - mutating func compress(_ input: [UInt8], into output: inout ByteBuffer) throws -> Int { - precondition(self.isInitialized) + func compress(_ input: [UInt8], into output: inout ByteBuffer) throws -> Int { defer { self.reset() } let upperBound = self.stream.deflateBound(inputBytes: input.count) return try self.stream.deflate(input, into: &output, upperBound: upperBound) } /// Resets compression state. - private mutating func reset() { + private func reset() { do { try self.stream.deflateReset() } catch { @@ -87,7 +81,7 @@ extension Zlib { } /// Deallocates any resources allocated by Zlib. - mutating func end() { + private func end() { self.stream.deflateEnd() } } @@ -96,22 +90,20 @@ extension Zlib { extension Zlib { /// Creates a new decompressor for the given compression format. /// - /// This decompressor is only suitable for compressing whole messages at a time. Callers - /// must ``initialize()`` the decompressor before using it. - struct Decompressor { + /// This decompressor is only suitable for compressing whole messages at a time. + final class Decompressor { + // Note: this is intentionally a class, see the note in Zlib.Compressor. private var stream: z_stream private let method: Method - private var isInitialized = false init(method: Method) { self.method = method self.stream = z_stream() + self.stream.inflateInit(windowBits: self.method.windowBits) } - mutating func initialize() { - precondition(!self.isInitialized) - self.stream.inflateInit(windowBits: self.method.windowBits) - self.isInitialized = true + deinit { + self.end() } /// Returns the decompressed bytes from ``input``. @@ -119,14 +111,13 @@ extension Zlib { /// - Parameters: /// - input: The buffer read compressed bytes from. /// - limit: The largest size a decompressed payload may be. - mutating func decompress(_ input: inout ByteBuffer, limit: Int) throws -> [UInt8] { - precondition(self.isInitialized) + func decompress(_ input: inout ByteBuffer, limit: Int) throws -> [UInt8] { defer { self.reset() } return try self.stream.inflate(input: &input, limit: limit) } /// Resets decompression state. - private mutating func reset() { + private func reset() { do { try self.stream.inflateReset() } catch { @@ -137,7 +128,7 @@ extension Zlib { } /// Deallocates any resources allocated by Zlib. - mutating func end() { + private func end() { self.stream.inflateEnd() } } diff --git a/Tests/GRPCHTTP2CoreTests/Server/Compression/ZlibTests.swift b/Tests/GRPCHTTP2CoreTests/Server/Compression/ZlibTests.swift index f0c8ce753..661a64ed2 100644 --- a/Tests/GRPCHTTP2CoreTests/Server/Compression/ZlibTests.swift +++ b/Tests/GRPCHTTP2CoreTests/Server/Compression/ZlibTests.swift @@ -31,10 +31,7 @@ final class ZlibTests: XCTestCase { """ private func compress(_ input: [UInt8], method: Zlib.Method) throws -> ByteBuffer { - var compressor = Zlib.Compressor(method: method) - compressor.initialize() - defer { compressor.end() } - + let compressor = Zlib.Compressor(method: method) var buffer = ByteBuffer() try compressor.compress(input, into: &buffer) return buffer @@ -45,10 +42,7 @@ final class ZlibTests: XCTestCase { method: Zlib.Method, limit: Int = .max ) throws -> [UInt8] { - var decompressor = Zlib.Decompressor(method: method) - decompressor.initialize() - defer { decompressor.end() } - + let decompressor = Zlib.Decompressor(method: method) var input = input return try decompressor.decompress(&input, limit: limit) } @@ -69,9 +63,7 @@ final class ZlibTests: XCTestCase { func testRepeatedCompresses() throws { let original = Array(self.text.utf8) - var compressor = Zlib.Compressor(method: .deflate) - compressor.initialize() - defer { compressor.end() } + let compressor = Zlib.Compressor(method: .deflate) var compressed = ByteBuffer() let bytesWritten = try compressor.compress(original, into: &compressed) @@ -86,9 +78,7 @@ final class ZlibTests: XCTestCase { func testRepeatedDecompresses() throws { let original = Array(self.text.utf8) - var decompressor = Zlib.Decompressor(method: .deflate) - decompressor.initialize() - defer { decompressor.end() } + let decompressor = Zlib.Decompressor(method: .deflate) let compressed = try self.compress(original, method: .deflate) var input = compressed @@ -123,9 +113,7 @@ final class ZlibTests: XCTestCase { } func testCompressAppendsToBuffer() throws { - var compressor = Zlib.Compressor(method: .deflate) - compressor.initialize() - defer { compressor.end() } + let compressor = Zlib.Compressor(method: .deflate) var buffer = ByteBuffer() try compressor.compress(Array(repeating: 0, count: 1024), into: &buffer) From 6a428ca0339ca02800aaf6bb8bde801e87e36bde Mon Sep 17 00:00:00 2001 From: George Barnett Date: Wed, 24 Jan 2024 10:27:59 +0000 Subject: [PATCH 2/4] Revert "Make Zlib.Compressor/Decompressor classes" This reverts commit c68e980d8462f36a91e693d1273c3065c1355acb. --- Sources/GRPCHTTP2Core/Compression/Zlib.swift | 51 +++++++++++-------- .../Server/Compression/ZlibTests.swift | 22 ++++++-- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/Sources/GRPCHTTP2Core/Compression/Zlib.swift b/Sources/GRPCHTTP2Core/Compression/Zlib.swift index dd513dd0d..f8abeff98 100644 --- a/Sources/GRPCHTTP2Core/Compression/Zlib.swift +++ b/Sources/GRPCHTTP2Core/Compression/Zlib.swift @@ -37,24 +37,29 @@ enum Zlib { extension Zlib { /// Creates a new compressor for the given compression format. /// - /// This compressor is only suitable for compressing whole messages at a time. - final class Compressor { - // Note: the compressor and decompressor are classes. This is intentional as a z_stream stores - // a pointer back to itself within its internal state. Calls to deflate and inflate do a state - // check ensuring that the stream pointer and its pointer-to-self held by its internal state - // are the same. However, within a struct held on the stack this location can change and results - // in errors in deflate/inflate. + /// This compressor is only suitable for compressing whole messages at a time. Callers + /// must ``initialize()`` the compressor before using it. + struct Compressor { private var stream: z_stream private let method: Method + private var isInitialized = false init(method: Method) { self.method = method self.stream = z_stream() + } + + /// Initialize the compressor. + mutating func initialize() { + precondition(!self.isInitialized) self.stream.deflateInit(windowBits: self.method.windowBits) + self.isInitialized = true } - deinit { - self.end() + static func initialized(_ method: Method) -> Self { + var compressor = Compressor(method: method) + compressor.initialize() + return compressor } /// Compresses the data in `input` into the `output` buffer. @@ -63,14 +68,15 @@ extension Zlib { /// - Parameter output: The `ByteBuffer` into which the compressed message should be written. /// - Returns: The number of bytes written into the `output` buffer. @discardableResult - func compress(_ input: [UInt8], into output: inout ByteBuffer) throws -> Int { + mutating func compress(_ input: [UInt8], into output: inout ByteBuffer) throws -> Int { + precondition(self.isInitialized) defer { self.reset() } let upperBound = self.stream.deflateBound(inputBytes: input.count) return try self.stream.deflate(input, into: &output, upperBound: upperBound) } /// Resets compression state. - private func reset() { + private mutating func reset() { do { try self.stream.deflateReset() } catch { @@ -81,7 +87,7 @@ extension Zlib { } /// Deallocates any resources allocated by Zlib. - private func end() { + mutating func end() { self.stream.deflateEnd() } } @@ -90,20 +96,22 @@ extension Zlib { extension Zlib { /// Creates a new decompressor for the given compression format. /// - /// This decompressor is only suitable for compressing whole messages at a time. - final class Decompressor { - // Note: this is intentionally a class, see the note in Zlib.Compressor. + /// This decompressor is only suitable for compressing whole messages at a time. Callers + /// must ``initialize()`` the decompressor before using it. + struct Decompressor { private var stream: z_stream private let method: Method + private var isInitialized = false init(method: Method) { self.method = method self.stream = z_stream() - self.stream.inflateInit(windowBits: self.method.windowBits) } - deinit { - self.end() + mutating func initialize() { + precondition(!self.isInitialized) + self.stream.inflateInit(windowBits: self.method.windowBits) + self.isInitialized = true } /// Returns the decompressed bytes from ``input``. @@ -111,13 +119,14 @@ extension Zlib { /// - Parameters: /// - input: The buffer read compressed bytes from. /// - limit: The largest size a decompressed payload may be. - func decompress(_ input: inout ByteBuffer, limit: Int) throws -> [UInt8] { + mutating func decompress(_ input: inout ByteBuffer, limit: Int) throws -> [UInt8] { + precondition(self.isInitialized) defer { self.reset() } return try self.stream.inflate(input: &input, limit: limit) } /// Resets decompression state. - private func reset() { + private mutating func reset() { do { try self.stream.inflateReset() } catch { @@ -128,7 +137,7 @@ extension Zlib { } /// Deallocates any resources allocated by Zlib. - private func end() { + mutating func end() { self.stream.inflateEnd() } } diff --git a/Tests/GRPCHTTP2CoreTests/Server/Compression/ZlibTests.swift b/Tests/GRPCHTTP2CoreTests/Server/Compression/ZlibTests.swift index 661a64ed2..f0c8ce753 100644 --- a/Tests/GRPCHTTP2CoreTests/Server/Compression/ZlibTests.swift +++ b/Tests/GRPCHTTP2CoreTests/Server/Compression/ZlibTests.swift @@ -31,7 +31,10 @@ final class ZlibTests: XCTestCase { """ private func compress(_ input: [UInt8], method: Zlib.Method) throws -> ByteBuffer { - let compressor = Zlib.Compressor(method: method) + var compressor = Zlib.Compressor(method: method) + compressor.initialize() + defer { compressor.end() } + var buffer = ByteBuffer() try compressor.compress(input, into: &buffer) return buffer @@ -42,7 +45,10 @@ final class ZlibTests: XCTestCase { method: Zlib.Method, limit: Int = .max ) throws -> [UInt8] { - let decompressor = Zlib.Decompressor(method: method) + var decompressor = Zlib.Decompressor(method: method) + decompressor.initialize() + defer { decompressor.end() } + var input = input return try decompressor.decompress(&input, limit: limit) } @@ -63,7 +69,9 @@ final class ZlibTests: XCTestCase { func testRepeatedCompresses() throws { let original = Array(self.text.utf8) - let compressor = Zlib.Compressor(method: .deflate) + var compressor = Zlib.Compressor(method: .deflate) + compressor.initialize() + defer { compressor.end() } var compressed = ByteBuffer() let bytesWritten = try compressor.compress(original, into: &compressed) @@ -78,7 +86,9 @@ final class ZlibTests: XCTestCase { func testRepeatedDecompresses() throws { let original = Array(self.text.utf8) - let decompressor = Zlib.Decompressor(method: .deflate) + var decompressor = Zlib.Decompressor(method: .deflate) + decompressor.initialize() + defer { decompressor.end() } let compressed = try self.compress(original, method: .deflate) var input = compressed @@ -113,7 +123,9 @@ final class ZlibTests: XCTestCase { } func testCompressAppendsToBuffer() throws { - let compressor = Zlib.Compressor(method: .deflate) + var compressor = Zlib.Compressor(method: .deflate) + compressor.initialize() + defer { compressor.end() } var buffer = ByteBuffer() try compressor.compress(Array(repeating: 0, count: 1024), into: &buffer) From 22a8f432b28e401558971ea01fc2ddc01b0c0540 Mon Sep 17 00:00:00 2001 From: George Barnett Date: Wed, 24 Jan 2024 10:28:19 +0000 Subject: [PATCH 3/4] remove initialized --- Sources/GRPCHTTP2Core/Compression/Zlib.swift | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Sources/GRPCHTTP2Core/Compression/Zlib.swift b/Sources/GRPCHTTP2Core/Compression/Zlib.swift index f8abeff98..c0763f62f 100644 --- a/Sources/GRPCHTTP2Core/Compression/Zlib.swift +++ b/Sources/GRPCHTTP2Core/Compression/Zlib.swift @@ -56,12 +56,6 @@ extension Zlib { self.isInitialized = true } - static func initialized(_ method: Method) -> Self { - var compressor = Compressor(method: method) - compressor.initialize() - return compressor - } - /// Compresses the data in `input` into the `output` buffer. /// /// - Parameter input: The complete data to be compressed. From 3efba73b10568fe8f358fd6131cefa30f9188e39 Mon Sep 17 00:00:00 2001 From: George Barnett Date: Wed, 24 Jan 2024 11:02:27 +0000 Subject: [PATCH 4/4] Use a pointer to a z_stream --- Sources/GRPCHTTP2Core/Compression/Zlib.swift | 155 +++++++++--------- .../Server/Compression/ZlibTests.swift | 15 +- 2 files changed, 78 insertions(+), 92 deletions(-) diff --git a/Sources/GRPCHTTP2Core/Compression/Zlib.swift b/Sources/GRPCHTTP2Core/Compression/Zlib.swift index c0763f62f..b94bd8a1d 100644 --- a/Sources/GRPCHTTP2Core/Compression/Zlib.swift +++ b/Sources/GRPCHTTP2Core/Compression/Zlib.swift @@ -37,23 +37,18 @@ enum Zlib { extension Zlib { /// Creates a new compressor for the given compression format. /// - /// This compressor is only suitable for compressing whole messages at a time. Callers - /// must ``initialize()`` the compressor before using it. + /// This compressor is only suitable for compressing whole messages at a time. struct Compressor { - private var stream: z_stream + // TODO: Make this ~Copyable when 5.9 is the lowest supported Swift version. + + private var stream: UnsafeMutablePointer private let method: Method - private var isInitialized = false init(method: Method) { self.method = method - self.stream = z_stream() - } - - /// Initialize the compressor. - mutating func initialize() { - precondition(!self.isInitialized) + self.stream = .allocate(capacity: 1) + self.stream.initialize(to: z_stream()) self.stream.deflateInit(windowBits: self.method.windowBits) - self.isInitialized = true } /// Compresses the data in `input` into the `output` buffer. @@ -62,27 +57,27 @@ extension Zlib { /// - Parameter output: The `ByteBuffer` into which the compressed message should be written. /// - Returns: The number of bytes written into the `output` buffer. @discardableResult - mutating func compress(_ input: [UInt8], into output: inout ByteBuffer) throws -> Int { - precondition(self.isInitialized) + func compress(_ input: [UInt8], into output: inout ByteBuffer) throws -> Int { defer { self.reset() } let upperBound = self.stream.deflateBound(inputBytes: input.count) return try self.stream.deflate(input, into: &output, upperBound: upperBound) } /// Resets compression state. - private mutating func reset() { + private func reset() { do { try self.stream.deflateReset() } catch { self.end() - self.stream = z_stream() + self.stream.initialize(to: z_stream()) self.stream.deflateInit(windowBits: self.method.windowBits) } } /// Deallocates any resources allocated by Zlib. - mutating func end() { + func end() { self.stream.deflateEnd() + self.stream.deallocate() } } } @@ -90,22 +85,18 @@ extension Zlib { extension Zlib { /// Creates a new decompressor for the given compression format. /// - /// This decompressor is only suitable for compressing whole messages at a time. Callers - /// must ``initialize()`` the decompressor before using it. + /// This decompressor is only suitable for compressing whole messages at a time. struct Decompressor { - private var stream: z_stream + // TODO: Make this ~Copyable when 5.9 is the lowest supported Swift version. + + private var stream: UnsafeMutablePointer private let method: Method - private var isInitialized = false init(method: Method) { self.method = method - self.stream = z_stream() - } - - mutating func initialize() { - precondition(!self.isInitialized) + self.stream = UnsafeMutablePointer.allocate(capacity: 1) + self.stream.initialize(to: z_stream()) self.stream.inflateInit(windowBits: self.method.windowBits) - self.isInitialized = true } /// Returns the decompressed bytes from ``input``. @@ -113,26 +104,26 @@ extension Zlib { /// - Parameters: /// - input: The buffer read compressed bytes from. /// - limit: The largest size a decompressed payload may be. - mutating func decompress(_ input: inout ByteBuffer, limit: Int) throws -> [UInt8] { - precondition(self.isInitialized) + func decompress(_ input: inout ByteBuffer, limit: Int) throws -> [UInt8] { defer { self.reset() } return try self.stream.inflate(input: &input, limit: limit) } /// Resets decompression state. - private mutating func reset() { + private func reset() { do { try self.stream.inflateReset() } catch { self.end() - self.stream = z_stream() + self.stream.initialize(to: z_stream()) self.stream.inflateInit(windowBits: self.method.windowBits) } } /// Deallocates any resources allocated by Zlib. - mutating func end() { + func end() { self.stream.inflateEnd() + self.stream.deallocate() } } } @@ -149,13 +140,13 @@ struct ZlibError: Error, Hashable { } } -extension z_stream { - mutating func inflateInit(windowBits: Int32) { - self.zfree = nil - self.zalloc = nil - self.opaque = nil +extension UnsafeMutablePointer { + func inflateInit(windowBits: Int32) { + self.pointee.zfree = nil + self.pointee.zalloc = nil + self.pointee.opaque = nil - let rc = CGRPCZlib_inflateInit2(&self, windowBits) + let rc = CGRPCZlib_inflateInit2(self, windowBits) // Possible return codes: // - Z_OK // - Z_MEM_ERROR: not enough memory @@ -165,8 +156,8 @@ extension z_stream { precondition(rc == Z_OK, "inflateInit2 failed with error (\(rc)) \(self.lastError ?? "")") } - mutating func inflateReset() throws { - let rc = CGRPCZlib_inflateReset(&self) + func inflateReset() throws { + let rc = CGRPCZlib_inflateReset(self) // Possible return codes: // - Z_OK @@ -181,17 +172,17 @@ extension z_stream { } } - mutating func inflateEnd() { - _ = CGRPCZlib_inflateEnd(&self) + func inflateEnd() { + _ = CGRPCZlib_inflateEnd(self) } - mutating func deflateInit(windowBits: Int32) { - self.zfree = nil - self.zalloc = nil - self.opaque = nil + func deflateInit(windowBits: Int32) { + self.pointee.zfree = nil + self.pointee.zalloc = nil + self.pointee.opaque = nil let rc = CGRPCZlib_deflateInit2( - &self, + self, Z_DEFAULT_COMPRESSION, // compression level Z_DEFLATED, // compression method (this must be Z_DEFLATED) windowBits, // window size, i.e. deflate/gzip @@ -209,8 +200,8 @@ extension z_stream { precondition(rc == Z_OK, "deflateInit2 failed with error (\(rc)) \(self.lastError ?? "")") } - mutating func deflateReset() throws { - let rc = CGRPCZlib_deflateReset(&self) + func deflateReset() throws { + let rc = CGRPCZlib_deflateReset(self) // Possible return codes: // - Z_OK @@ -225,87 +216,87 @@ extension z_stream { } } - mutating func deflateEnd() { - _ = CGRPCZlib_deflateEnd(&self) + func deflateEnd() { + _ = CGRPCZlib_deflateEnd(self) } - mutating func deflateBound(inputBytes: Int) -> Int { - let bound = CGRPCZlib_deflateBound(&self, UInt(inputBytes)) + func deflateBound(inputBytes: Int) -> Int { + let bound = CGRPCZlib_deflateBound(self, UInt(inputBytes)) return Int(bound) } - mutating func setNextInputBuffer(_ buffer: UnsafeMutableBufferPointer) { + func setNextInputBuffer(_ buffer: UnsafeMutableBufferPointer) { if let baseAddress = buffer.baseAddress { - self.next_in = baseAddress - self.avail_in = UInt32(buffer.count) + self.pointee.next_in = baseAddress + self.pointee.avail_in = UInt32(buffer.count) } else { - self.next_in = nil - self.avail_in = 0 + self.pointee.next_in = nil + self.pointee.avail_in = 0 } } - mutating func setNextInputBuffer(_ buffer: UnsafeMutableRawBufferPointer?) { + func setNextInputBuffer(_ buffer: UnsafeMutableRawBufferPointer?) { if let buffer = buffer, let baseAddress = buffer.baseAddress { - self.next_in = CGRPCZlib_castVoidToBytefPointer(baseAddress) - self.avail_in = UInt32(buffer.count) + self.pointee.next_in = CGRPCZlib_castVoidToBytefPointer(baseAddress) + self.pointee.avail_in = UInt32(buffer.count) } else { - self.next_in = nil - self.avail_in = 0 + self.pointee.next_in = nil + self.pointee.avail_in = 0 } } - mutating func setNextOutputBuffer(_ buffer: UnsafeMutableBufferPointer) { + func setNextOutputBuffer(_ buffer: UnsafeMutableBufferPointer) { if let baseAddress = buffer.baseAddress { - self.next_out = baseAddress - self.avail_out = UInt32(buffer.count) + self.pointee.next_out = baseAddress + self.pointee.avail_out = UInt32(buffer.count) } else { - self.next_out = nil - self.avail_out = 0 + self.pointee.next_out = nil + self.pointee.avail_out = 0 } } - mutating func setNextOutputBuffer(_ buffer: UnsafeMutableRawBufferPointer?) { + func setNextOutputBuffer(_ buffer: UnsafeMutableRawBufferPointer?) { if let buffer = buffer, let baseAddress = buffer.baseAddress { - self.next_out = CGRPCZlib_castVoidToBytefPointer(baseAddress) - self.avail_out = UInt32(buffer.count) + self.pointee.next_out = CGRPCZlib_castVoidToBytefPointer(baseAddress) + self.pointee.avail_out = UInt32(buffer.count) } else { - self.next_out = nil - self.avail_out = 0 + self.pointee.next_out = nil + self.pointee.avail_out = 0 } } /// Number of bytes available to read `self.nextInputBuffer`. See also: `z_stream.avail_in`. var availableInputBytes: Int { get { - Int(self.avail_in) + Int(self.pointee.avail_in) } set { - self.avail_in = UInt32(newValue) + self.pointee.avail_in = UInt32(newValue) } } /// The remaining writable space in `nextOutputBuffer`. See also: `z_stream.avail_out`. var availableOutputBytes: Int { get { - Int(self.avail_out) + Int(self.pointee.avail_out) } set { - self.avail_out = UInt32(newValue) + self.pointee.avail_out = UInt32(newValue) } } /// The total number of bytes written to the output buffer. See also: `z_stream.total_out`. var totalOutputBytes: Int { - Int(self.total_out) + Int(self.pointee.total_out) } /// The last error message that zlib wrote. No message is guaranteed on error, however, `nil` is /// guaranteed if there is no error. See also `z_stream.msg`. var lastError: String? { - self.msg.map { String(cString: $0) } + self.pointee.msg.map { String(cString: $0) } } - mutating func inflate(input: inout ByteBuffer, limit: Int) throws -> [UInt8] { + func inflate(input: inout ByteBuffer, limit: Int) throws -> [UInt8] { return try input.readWithUnsafeMutableReadableBytes { inputPointer in self.setNextInputBuffer(inputPointer) defer { @@ -336,7 +327,7 @@ extension z_stream { // // Note that Z_OK is not okay here since we always flush with Z_FINISH and therefore // use Z_STREAM_END as our success criteria. - let rc = CGRPCZlib_inflate(&self, Z_FINISH) + let rc = CGRPCZlib_inflate(self, Z_FINISH) switch rc { case Z_STREAM_END: finished = true @@ -371,7 +362,7 @@ extension z_stream { } } - mutating func deflate( + func deflate( _ input: [UInt8], into output: inout ByteBuffer, upperBound: Int @@ -388,7 +379,7 @@ extension z_stream { return try output.writeWithUnsafeMutableBytes(minimumWritableBytes: upperBound) { output in self.setNextOutputBuffer(output) - let rc = CGRPCZlib_deflate(&self, Z_FINISH) + let rc = CGRPCZlib_deflate(self, Z_FINISH) // Possible return codes: // - Z_OK: some progress has been made diff --git a/Tests/GRPCHTTP2CoreTests/Server/Compression/ZlibTests.swift b/Tests/GRPCHTTP2CoreTests/Server/Compression/ZlibTests.swift index f0c8ce753..bcee1f3e2 100644 --- a/Tests/GRPCHTTP2CoreTests/Server/Compression/ZlibTests.swift +++ b/Tests/GRPCHTTP2CoreTests/Server/Compression/ZlibTests.swift @@ -31,8 +31,7 @@ final class ZlibTests: XCTestCase { """ private func compress(_ input: [UInt8], method: Zlib.Method) throws -> ByteBuffer { - var compressor = Zlib.Compressor(method: method) - compressor.initialize() + let compressor = Zlib.Compressor(method: method) defer { compressor.end() } var buffer = ByteBuffer() @@ -45,8 +44,7 @@ final class ZlibTests: XCTestCase { method: Zlib.Method, limit: Int = .max ) throws -> [UInt8] { - var decompressor = Zlib.Decompressor(method: method) - decompressor.initialize() + let decompressor = Zlib.Decompressor(method: method) defer { decompressor.end() } var input = input @@ -69,8 +67,7 @@ final class ZlibTests: XCTestCase { func testRepeatedCompresses() throws { let original = Array(self.text.utf8) - var compressor = Zlib.Compressor(method: .deflate) - compressor.initialize() + let compressor = Zlib.Compressor(method: .deflate) defer { compressor.end() } var compressed = ByteBuffer() @@ -86,8 +83,7 @@ final class ZlibTests: XCTestCase { func testRepeatedDecompresses() throws { let original = Array(self.text.utf8) - var decompressor = Zlib.Decompressor(method: .deflate) - decompressor.initialize() + let decompressor = Zlib.Decompressor(method: .deflate) defer { decompressor.end() } let compressed = try self.compress(original, method: .deflate) @@ -123,8 +119,7 @@ final class ZlibTests: XCTestCase { } func testCompressAppendsToBuffer() throws { - var compressor = Zlib.Compressor(method: .deflate) - compressor.initialize() + let compressor = Zlib.Compressor(method: .deflate) defer { compressor.end() } var buffer = ByteBuffer()