From e8f3efc2daafd9f97c8e9bd3cd1d8bc66f63079d Mon Sep 17 00:00:00 2001 From: George Barnett Date: Tue, 13 Feb 2024 18:10:28 +0000 Subject: [PATCH 1/3] Remove NIO dependency (#20) Motivation: NIO's ByteBuffer is used as an implementation detail for parsing responses in the DNSD implementation. However NIO is quite a heavy dependency so we should avoid it if possible. Modifications: - Use `ArraySlice` instead of `ByteBuffer` and remove the dependency on SwiftNIO Result: No dependency on SwiftNIO --- Package.swift | 2 - .../dnssd/DNSResolver_dnssd.swift | 42 +++++++++++--- .../dnssd/DNSDArraySliceTests.swift | 55 +++++++++++++++++++ 3 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 Tests/AsyncDNSResolverTests/dnssd/DNSDArraySliceTests.swift diff --git a/Package.swift b/Package.swift index f8a01bc..d602246 100644 --- a/Package.swift +++ b/Package.swift @@ -29,7 +29,6 @@ let package = Package( .library(name: "AsyncDNSResolver", targets: ["AsyncDNSResolver"]), ], dependencies: [ - .package(url: "https://github.com/apple/swift-nio", .upToNextMajor(from: "2.53.0")), .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), ], targets: [ @@ -49,7 +48,6 @@ let package = Package( name: "AsyncDNSResolver", dependencies: [ "CAsyncDNSResolver", - .product(name: "NIOCore", package: "swift-nio"), ] ), diff --git a/Sources/AsyncDNSResolver/dnssd/DNSResolver_dnssd.swift b/Sources/AsyncDNSResolver/dnssd/DNSResolver_dnssd.swift index 4875128..548b279 100644 --- a/Sources/AsyncDNSResolver/dnssd/DNSResolver_dnssd.swift +++ b/Sources/AsyncDNSResolver/dnssd/DNSResolver_dnssd.swift @@ -14,7 +14,6 @@ #if canImport(Darwin) import dnssd -import NIOCore /// ``DNSResolver`` implementation backed by dnssd framework. public struct DNSSDDNSResolver: DNSResolver { @@ -267,7 +266,7 @@ extension DNSSD { } let bufferPtr = UnsafeBufferPointer(start: ptr, count: Int(length)) - var buffer = ByteBuffer(bytes: bufferPtr) + var buffer = Array(bufferPtr)[...] guard let nameserver = self.readName(&buffer) else { throw AsyncDNSResolver.Error.badResponse("failed to read name") @@ -290,7 +289,7 @@ extension DNSSD { } let bufferPtr = UnsafeBufferPointer(start: ptr, count: Int(length)) - var buffer = ByteBuffer(bytes: bufferPtr) + var buffer = Array(bufferPtr)[...] guard let cname = self.readName(&buffer) else { throw AsyncDNSResolver.Error.badResponse("failed to read name") @@ -313,7 +312,7 @@ extension DNSSD { } let bufferPtr = UnsafeBufferPointer(start: ptr, count: Int(length)) - var buffer = ByteBuffer(bytes: bufferPtr) + var buffer = Array(bufferPtr)[...] guard let mname = self.readName(&buffer), let rname = self.readName(&buffer), @@ -350,7 +349,7 @@ extension DNSSD { } let bufferPtr = UnsafeBufferPointer(start: ptr, count: Int(length)) - var buffer = ByteBuffer(bytes: bufferPtr) + var buffer = Array(bufferPtr)[...] guard let name = self.readName(&buffer) else { throw AsyncDNSResolver.Error.badResponse("failed to read name") @@ -373,7 +372,7 @@ extension DNSSD { } let bufferPtr = UnsafeBufferPointer(start: ptr, count: Int(length)) - var buffer = ByteBuffer(bytes: bufferPtr) + var buffer = Array(bufferPtr)[...] guard let priority = buffer.readInteger(as: UInt16.self), let host = self.readName(&buffer) else { @@ -416,7 +415,7 @@ extension DNSSD { } let bufferPtr = UnsafeBufferPointer(start: ptr, count: Int(length)) - var buffer = ByteBuffer(bytes: bufferPtr) + var buffer = Array(bufferPtr)[...] guard let priority = buffer.readInteger(as: UInt16.self), let weight = buffer.readInteger(as: UInt16.self), @@ -440,13 +439,14 @@ extension DNSSD { } extension DNSSDQueryReplyHandler { - func readName(_ buffer: inout ByteBuffer) -> String? { + func readName(_ buffer: inout ArraySlice) -> String? { var parts: [String] = [] while let length = buffer.readInteger(as: UInt8.self), length > 0, let part = buffer.readString(length: Int(length)) { parts.append(part) } + return parts.isEmpty ? nil : parts.joined(separator: ".") } @@ -460,4 +460,30 @@ extension DNSSDQueryReplyHandler { return record } } + +extension ArraySlice { + mutating func readInteger(as: T.Type = T.self) -> T? { + let size = MemoryLayout.size + guard self.count >= size else { return nil } + + let value = self.withUnsafeBytes { pointer in + var value = T.zero + Swift.withUnsafeMutableBytes(of: &value) { valuePointer in + valuePointer.copyMemory(from: UnsafeRawBufferPointer(rebasing: pointer[.. String? { + guard self.count >= length else { return nil } + + let prefix = self.prefix(length) + self = self.dropFirst(length) + return String(decoding: prefix, as: UTF8.self) + } +} #endif diff --git a/Tests/AsyncDNSResolverTests/dnssd/DNSDArraySliceTests.swift b/Tests/AsyncDNSResolverTests/dnssd/DNSDArraySliceTests.swift new file mode 100644 index 0000000..15a5a8a --- /dev/null +++ b/Tests/AsyncDNSResolverTests/dnssd/DNSDArraySliceTests.swift @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAsyncDNSResolver open source project +// +// Copyright (c) 2024 Apple Inc. and the SwiftAsyncDNSResolver project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftAsyncDNSResolver project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +@testable import AsyncDNSResolver +import XCTest + +#if canImport(Darwin) +final class DNSDArraySliceTests: XCTestCase { + func testReadUnsignedInteger() { + // [UInt8(0), UInt16(.max), UInt32(0), UInt64(.max)] + let bytes: [UInt8] = [0, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255] + var slice = bytes[...] + + XCTAssertEqual(slice.readInteger(as: UInt8.self), 0) + XCTAssertEqual(slice.readInteger(as: UInt16.self), .max) + XCTAssertEqual(slice.readInteger(as: UInt32.self), 0) + XCTAssertEqual(slice.readInteger(as: UInt64.self), .max) + + XCTAssertNil(slice.readInteger(as: UInt8.self)) + } + + func testReadSignedInteger() { + // [Int8(0), Int16(-1), Int32(0), Int64(-1)] + let bytes: [UInt8] = [0, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255] + var slice = bytes[...] + + XCTAssertEqual(slice.readInteger(as: Int8.self), 0) + XCTAssertEqual(slice.readInteger(as: Int16.self), -1) + XCTAssertEqual(slice.readInteger(as: Int32.self), 0) + XCTAssertEqual(slice.readInteger(as: Int64.self), -1) + + XCTAssertNil(slice.readInteger(as: Int8.self)) + } + + func testReadString() { + let bytes = Array("hello, world!".utf8) + var slice = bytes[...] + + XCTAssertEqual(slice.readString(length: 13), "hello, world!") + XCTAssertEqual(slice.readString(length: 0), "") + XCTAssertNil(slice.readString(length: 1)) + } +} +#endif From 62fbedd992abf97e83549dde7c7cf9ab7b74c8d8 Mon Sep 17 00:00:00 2001 From: Yim Lee Date: Wed, 14 Feb 2024 00:02:00 -0800 Subject: [PATCH 2/3] Move platform availability to types (#22) Motivation: Having `platforms` in `Package.swift` might prevent others from adopting this library. Modifications: - Move platform availability to types - Remove `platforms` in `Package.swift` - macOS 10.15 seems to be sufficient, so lowering it from v13.0 --- Package.swift | 4 ---- Sources/AsyncDNSResolver/AsyncDNSResolver.swift | 3 ++- Sources/AsyncDNSResolver/Errors.swift | 3 ++- Sources/AsyncDNSResolver/c-ares/AresChannel.swift | 4 +++- Sources/AsyncDNSResolver/c-ares/AresOptions.swift | 5 ++++- Sources/AsyncDNSResolver/c-ares/DNSResolver_c-ares.swift | 5 +++++ Sources/AsyncDNSResolver/c-ares/Errors_c-ares.swift | 3 ++- Sources/AsyncDNSResolver/dnssd/DNSResolver_dnssd.swift | 7 ++++++- scripts/soundness.sh | 2 +- 9 files changed, 25 insertions(+), 11 deletions(-) diff --git a/Package.swift b/Package.swift index d602246..a185218 100644 --- a/Package.swift +++ b/Package.swift @@ -21,10 +21,6 @@ do { let package = Package( name: "swift-async-dns-resolver", - platforms: [ - .macOS("13.0"), - .iOS(.v13), - ], products: [ .library(name: "AsyncDNSResolver", targets: ["AsyncDNSResolver"]), ], diff --git a/Sources/AsyncDNSResolver/AsyncDNSResolver.swift b/Sources/AsyncDNSResolver/AsyncDNSResolver.swift index 60cbc7e..1a9451f 100644 --- a/Sources/AsyncDNSResolver/AsyncDNSResolver.swift +++ b/Sources/AsyncDNSResolver/AsyncDNSResolver.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftAsyncDNSResolver open source project // -// Copyright (c) 2020-2023 Apple Inc. and the SwiftAsyncDNSResolver project authors +// Copyright (c) 2020-2024 Apple Inc. and the SwiftAsyncDNSResolver project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -15,6 +15,7 @@ // MARK: - Async DNS resolver API /// `AsyncDNSResolver` provides API for running asynchronous DNS queries. +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) public struct AsyncDNSResolver { let underlying: DNSResolver diff --git a/Sources/AsyncDNSResolver/Errors.swift b/Sources/AsyncDNSResolver/Errors.swift index ef4970d..7d1d930 100644 --- a/Sources/AsyncDNSResolver/Errors.swift +++ b/Sources/AsyncDNSResolver/Errors.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftAsyncDNSResolver open source project // -// Copyright (c) 2020-2023 Apple Inc. and the SwiftAsyncDNSResolver project authors +// Copyright (c) 2020-2024 Apple Inc. and the SwiftAsyncDNSResolver project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension AsyncDNSResolver { /// Possible ``AsyncDNSResolver/AsyncDNSResolver`` errors. public struct Error: Swift.Error, CustomStringConvertible { diff --git a/Sources/AsyncDNSResolver/c-ares/AresChannel.swift b/Sources/AsyncDNSResolver/c-ares/AresChannel.swift index 78b9d26..8f21422 100644 --- a/Sources/AsyncDNSResolver/c-ares/AresChannel.swift +++ b/Sources/AsyncDNSResolver/c-ares/AresChannel.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftAsyncDNSResolver open source project // -// Copyright (c) 2020-2023 Apple Inc. and the SwiftAsyncDNSResolver project authors +// Copyright (c) 2020-2024 Apple Inc. and the SwiftAsyncDNSResolver project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -17,6 +17,7 @@ import Foundation // MARK: - ares_channel +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) class AresChannel { let pointer: UnsafeMutablePointer let lock = NSLock() @@ -62,6 +63,7 @@ class AresChannel { } } +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) private func checkAresResult(body: () -> Int32) throws { let result = body() guard result == ARES_SUCCESS else { diff --git a/Sources/AsyncDNSResolver/c-ares/AresOptions.swift b/Sources/AsyncDNSResolver/c-ares/AresOptions.swift index 3b78118..3200667 100644 --- a/Sources/AsyncDNSResolver/c-ares/AresOptions.swift +++ b/Sources/AsyncDNSResolver/c-ares/AresOptions.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftAsyncDNSResolver open source project // -// Copyright (c) 2020-2023 Apple Inc. and the SwiftAsyncDNSResolver project authors +// Copyright (c) 2020-2024 Apple Inc. and the SwiftAsyncDNSResolver project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -16,6 +16,7 @@ import CAsyncDNSResolver // MARK: - Options for `CAresDNSResolver` +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension CAresDNSResolver { /// Options for ``CAresDNSResolver``. public struct Options { @@ -88,6 +89,7 @@ extension CAresDNSResolver { } } +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension CAresDNSResolver.Options { public struct Flags: OptionSet { public let rawValue: Int32 @@ -120,6 +122,7 @@ extension CAresDNSResolver.Options { } } +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension CAresDNSResolver.Options { var aresOptions: AresOptions { let aresOptions = AresOptions() diff --git a/Sources/AsyncDNSResolver/c-ares/DNSResolver_c-ares.swift b/Sources/AsyncDNSResolver/c-ares/DNSResolver_c-ares.swift index 657dd4c..0d217ad 100644 --- a/Sources/AsyncDNSResolver/c-ares/DNSResolver_c-ares.swift +++ b/Sources/AsyncDNSResolver/c-ares/DNSResolver_c-ares.swift @@ -15,6 +15,7 @@ import CAsyncDNSResolver /// ``DNSResolver`` implementation backed by c-ares C library. +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) public class CAresDNSResolver: DNSResolver { let options: Options let ares: Ares @@ -119,6 +120,7 @@ extension QueryType { // MARK: - c-ares query wrapper +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) class Ares { typealias QueryCallback = @convention(c) (UnsafeMutableRawPointer?, CInt, CInt, UnsafeMutablePointer?, CInt) -> Void @@ -183,6 +185,7 @@ class Ares { } } +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension Ares { // TODO: implement this more nicely using NIO EventLoop? // See: @@ -253,6 +256,7 @@ extension Ares { // MARK: - c-ares query reply handler +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension Ares { struct QueryReplyHandler { private let _handler: (CInt, UnsafeMutablePointer?, CInt) -> Void @@ -291,6 +295,7 @@ protocol AresQueryReplyParser { func parse(buffer: UnsafeMutablePointer?, length: CInt) throws -> Reply } +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension Ares { static let maxAddresses: Int = 32 diff --git a/Sources/AsyncDNSResolver/c-ares/Errors_c-ares.swift b/Sources/AsyncDNSResolver/c-ares/Errors_c-ares.swift index 8423d35..2e64937 100644 --- a/Sources/AsyncDNSResolver/c-ares/Errors_c-ares.swift +++ b/Sources/AsyncDNSResolver/c-ares/Errors_c-ares.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftAsyncDNSResolver open source project // -// Copyright (c) 2020-2023 Apple Inc. and the SwiftAsyncDNSResolver project authors +// Copyright (c) 2020-2024 Apple Inc. and the SwiftAsyncDNSResolver project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -14,6 +14,7 @@ import CAsyncDNSResolver +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension AsyncDNSResolver.Error { /// Create an ``AsyncDNSResolver/AsyncDNSResolver/Error`` from c-ares error code. init(code: Int32, _ description: String? = nil) { diff --git a/Sources/AsyncDNSResolver/dnssd/DNSResolver_dnssd.swift b/Sources/AsyncDNSResolver/dnssd/DNSResolver_dnssd.swift index 548b279..e33c97a 100644 --- a/Sources/AsyncDNSResolver/dnssd/DNSResolver_dnssd.swift +++ b/Sources/AsyncDNSResolver/dnssd/DNSResolver_dnssd.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftAsyncDNSResolver open source project // -// Copyright (c) 2023 Apple Inc. and the SwiftAsyncDNSResolver project authors +// Copyright (c) 2023-2024 Apple Inc. and the SwiftAsyncDNSResolver project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -16,6 +16,7 @@ import dnssd /// ``DNSResolver`` implementation backed by dnssd framework. +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) public struct DNSSDDNSResolver: DNSResolver { let dnssd: DNSSD @@ -98,6 +99,7 @@ extension QueryType { // MARK: - dnssd query wrapper +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) struct DNSSD { // Reference: https://gist.github.com/fikeminkel/a9c4bc4d0348527e8df3690e242038d3 func query( @@ -167,6 +169,7 @@ struct DNSSD { // MARK: - dnssd query reply handler +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension DNSSD { struct QueryReplyHandler { private let _handleRecord: (DNSServiceErrorType, UnsafeRawPointer?, UInt16) -> Void @@ -208,6 +211,7 @@ protocol DNSSDQueryReplyHandler { func generateReply(records: [Record]) throws -> Reply } +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension DNSSD { // Reference: https://github.com/orlandos-nl/DNSClient/blob/master/Sources/DNSClient/Messages/Message.swift @@ -450,6 +454,7 @@ extension DNSSDQueryReplyHandler { return parts.isEmpty ? nil : parts.joined(separator: ".") } + @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) func ensureOne(records: [R]) throws -> R { guard records.count <= 1 else { throw AsyncDNSResolver.Error.badResponse("expected 1 record but got \(records.count)") diff --git a/scripts/soundness.sh b/scripts/soundness.sh index a963865..efb44a4 100755 --- a/scripts/soundness.sh +++ b/scripts/soundness.sh @@ -18,7 +18,7 @@ here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" function replace_acceptable_years() { # this needs to replace all acceptable forms with 'YEARS' - sed -e 's/202[012]-202[1234]/YEARS/' -e 's/202[01234]/YEARS/' + sed -e 's/202[0123]-202[1234]/YEARS/' -e 's/202[01234]/YEARS/' } if ! hash swiftformat &> /dev/null From 96a18c67687e814edce555c86b1471c05345cb66 Mon Sep 17 00:00:00 2001 From: George Barnett Date: Wed, 14 Feb 2024 08:07:03 +0000 Subject: [PATCH 3/3] Add concrete IPv4 and IPv6 types (#21) Motivation: The `ARecord` and `AAAARecord` use the `IPAddress` `enum` as their address types. However, they should only use IPv4 and IPv6 addresses respectively. Modifications: - Add `IPAddress.IPv4` and IPAddress.IPv6` types and use them as the associated values in the `IPAddress` enum - Change the casing of the `IPAddress` cases from `.IPv4` and `.IPv6` to `.ipv4` and `.ipv6` as Swift case names are usually lower-camel case Result: - The types of IP address used by `ARecord` and `AAAARecord` are clearer --- .../AsyncDNSResolver/AsyncDNSResolver.swift | 34 ++++++++++++++----- .../c-ares/DNSResolver_c-ares.swift | 12 ++++--- .../dnssd/DNSResolver_dnssd.swift | 4 +-- .../dnssd/DNSSDDNSResolverTests.swift | 2 +- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/Sources/AsyncDNSResolver/AsyncDNSResolver.swift b/Sources/AsyncDNSResolver/AsyncDNSResolver.swift index 1a9451f..fb340e4 100644 --- a/Sources/AsyncDNSResolver/AsyncDNSResolver.swift +++ b/Sources/AsyncDNSResolver/AsyncDNSResolver.swift @@ -185,21 +185,39 @@ enum QueryType { // MARK: - Query reply types public enum IPAddress: Sendable, Equatable, CustomStringConvertible { - case IPv4(String) - case IPv6(String) + case ipv4(IPv4) + case ipv6(IPv6) public var description: String { switch self { - case .IPv4(let address): - return address - case .IPv6(let address): - return address + case .ipv4(let address): + return String(describing: address) + case .ipv6(let address): + return String(describing: address) + } + } + + public struct IPv4: Sendable, Hashable, CustomStringConvertible { + public var address: String + public var description: String { self.address } + + public init(address: String) { + self.address = address + } + } + + public struct IPv6: Sendable, Hashable, CustomStringConvertible { + public var address: String + public var description: String { self.address } + + public init(address: String) { + self.address = address } } } public struct ARecord: Sendable, Equatable, CustomStringConvertible { - public let address: IPAddress + public let address: IPAddress.IPv4 public let ttl: Int32? public var description: String { @@ -208,7 +226,7 @@ public struct ARecord: Sendable, Equatable, CustomStringConvertible { } public struct AAAARecord: Sendable, Equatable, CustomStringConvertible { - public let address: IPAddress + public let address: IPAddress.IPv6 public let ttl: Int32? public var description: String { diff --git a/Sources/AsyncDNSResolver/c-ares/DNSResolver_c-ares.swift b/Sources/AsyncDNSResolver/c-ares/DNSResolver_c-ares.swift index 0d217ad..c2fc3a4 100644 --- a/Sources/AsyncDNSResolver/c-ares/DNSResolver_c-ares.swift +++ b/Sources/AsyncDNSResolver/c-ares/DNSResolver_c-ares.swift @@ -579,32 +579,34 @@ private func toStringArray(_ arrayPointer: UnsafeMutablePointer [ARecord] { @@ -253,7 +253,7 @@ extension DNSSD { var parsedAddressBytes = [CChar](repeating: 0, count: Int(INET6_ADDRSTRLEN)) inet_ntop(AF_INET6, ptr, &parsedAddressBytes, socklen_t(INET6_ADDRSTRLEN)) let parsedAddress = String(cString: parsedAddressBytes) - return AAAARecord(address: .IPv6(parsedAddress), ttl: nil) + return AAAARecord(address: .init(address: parsedAddress), ttl: nil) } func generateReply(records: [AAAARecord]) throws -> [AAAARecord] { diff --git a/Tests/AsyncDNSResolverTests/dnssd/DNSSDDNSResolverTests.swift b/Tests/AsyncDNSResolverTests/dnssd/DNSSDDNSResolverTests.swift index acddf17..10aeb28 100644 --- a/Tests/AsyncDNSResolverTests/dnssd/DNSSDDNSResolverTests.swift +++ b/Tests/AsyncDNSResolverTests/dnssd/DNSSDDNSResolverTests.swift @@ -108,7 +108,7 @@ final class DNSSDDNSResolverTests: XCTestCase { let addrBytes: [UInt8] = [38, 32, 1, 73] try addrBytes.withUnsafeBufferPointer { let record = try DNSSD.AQueryReplyHandler.instance.parseRecord(data: $0.baseAddress, length: UInt16($0.count)) - XCTAssertEqual(record, ARecord(address: .IPv4("38.32.1.73"), ttl: nil)) + XCTAssertEqual(record, ARecord(address: .init(address: "38.32.1.73"), ttl: nil)) } }