import Foundation class IPAddress { private var inner: [UInt8] static var zero: IPAddress { IPAddress(parts: [0,0,0,0])! } init?(parts: [UInt8]) { guard parts.count == 4 else { return nil } self.inner = parts } init?(string: String) { self.inner = [0,0,0,0] let result = self.withUInt8Pointer { pointer in string.withCString { __IPAddressFromString(pointer, $0) } } guard result != 0 else { return nil } } init(copy other: IPAddress) { self.inner = other.inner } var string: String { let str = self.withUInt8Pointer { __stringIPAddress($0)! } defer { str.deallocate() } return String(cString: str) } var binary: String { let str = self.withUInt8Pointer { __binaryIPAddress($0)! } defer { str.deallocate() } return String(cString: str) } func withUInt8Pointer<Result>(_ body: (UnsafeMutablePointer<UInt8>) throws -> Result) rethrows -> Result { return try body(&self.inner) } subscript(index: Int) -> UInt8 { get { self.inner[index] } set { self.inner[index] = newValue } } } class Network { private let inner: UnsafeMutablePointer<__Network> lazy private(set) var address = { let address = self.inner.pointee.address return IPAddress(parts: [address.0, address.1, address.2, address.3])! }() lazy private(set) var mask = { let mask = self.inner.pointee.mask return IPAddress(parts: [mask.0, mask.1, mask.2, mask.3])! }() lazy private(set) var maskedBits = { var masked: UInt8 = 0 for i in 0..<4 { masked += (self.mask[i] >> 7) & 1 masked += (self.mask[i] >> 6) & 1 masked += (self.mask[i] >> 5) & 1 masked += (self.mask[i] >> 4) & 1 masked += (self.mask[i] >> 3) & 1 masked += (self.mask[i] >> 2) & 1 masked += (self.mask[i] >> 1) & 1 masked += (self.mask[i] >> 0) & 1 guard self.mask[i] == 0xff else { break } } return masked }() deinit { inner.deallocate() } init?(address: String, mask: UInt8) { guard let ntwk = address.withCString({ __CreateNetwork($0, mask) }) else { return nil } self.inner = ntwk } private init(inner: UnsafeMutablePointer<__Network>) { self.inner = inner } var description: String { let str = __CreateNetworkDescription(self.inner)! defer { str.deallocate() } return String(cString: str) } func subnetworks(hosts: [UInt32]) -> [Network]? { var zeroed = hosts + [0] guard let subnetworks = __CreateSubnetworks(self.inner, &zeroed) else { return nil } defer { subnetworks.deallocate() } return (0..<hosts.count).map { Network(inner: subnetworks[$0]!) } } var firstAddress: IPAddress { let address = IPAddress.zero address.withUInt8Pointer { __firstIPAddress($0, self.inner) } return address } var lastAddress: IPAddress { let address = IPAddress.zero address.withUInt8Pointer { __lastIPAddress($0, self.inner) } return address } }