//===----------------------------------------------------------------------===// // // This source file is taken from SwiftNIO open source project // // Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors // Licensed under Apache License v2.0 // //===----------------------------------------------------------------------===// // MARK:- Awful code begins here // Hello dear reader. Let me explain what we're doing here. // // From OpenSSL 1.0 to OpenSSL 1.1 one of the major breaking changes was the so-called // "great opaquifiying". Essentially, OpenSSL took all of its public structures and made // them opaque, such that they cannot be introspected from client code. This is a great // forward step, and brings them more in line with modern C library practices. // // However, it's an *enormous* inconvenience from Swift code. This is because the Swift // translation of the C type `SSL_CTX *` changed from `UnsafeMutablePointer` to // `OpaquePointer`. // // This change exists for reasonable enough reasons in Swift land (see // https://forums.swift.org/t/opaque-pointers-in-swift/6875 for a discussion), but // nonetheless causes enormous problems in our codebase. // // Our cheap way out is to make everything an OpaquePointer, and then provide initializers // between OpaquePointer and the typed pointers. This allows us to tolerate either pointer // type in our Swift code by bridging them over to OpaquePointer and back, and lets the // compiler worry about how exactly to make that work. // // Now, in fact, Swift already has initializers between the pointer types. What it does // not have is self-initializers: the ability to create an `OpaquePointer` from an `OpaquePointer`, // or an `UnsafePointer` from an `UnsafePointer`. We add those two initializers here. // We also add a special "make" function that exists to handle the special case of optional pointer // values, which we mostly encounter in the ALPN callbacks. // // The *downside* of this approach is that we totally break the pointer type system. It becomes // trivially possible to alias a pointer of type T to type U through two calls to init. This // is not a thing we want to widely promote. For this reason, these extensions are hidden in // this file, where we can laugh and jeer at them and generally make them feel bad about // themselves. // // Hopefully, in time, these extensions can be removed. extension UnsafePointer { init(_ ptr: UnsafePointer) { self = ptr } static func make(optional ptr: UnsafePointer?) -> UnsafePointer? { return ptr.map(UnsafePointer.init) } static func make(optional ptr: OpaquePointer?) -> UnsafePointer? { return ptr.map(UnsafePointer.init) } } extension UnsafeMutablePointer { init(_ ptr: UnsafeMutableRawPointer) { let x = UnsafeMutablePointer(bitPattern: UInt(bitPattern: ptr))! self = x } static func make(optional ptr: UnsafeMutablePointer?) -> UnsafeMutablePointer? { return ptr.map(UnsafeMutablePointer.init) } static func make(optional ptr: UnsafeMutableRawPointer?) -> UnsafeMutablePointer? { return ptr.map(UnsafeMutablePointer.init) } static func make(optional ptr: OpaquePointer?) -> UnsafeMutablePointer? { return ptr.map(UnsafeMutablePointer.init) } } extension UnsafeMutableRawPointer { static func make(optional ptr: OpaquePointer?) -> UnsafeMutableRawPointer? { return ptr.map(UnsafeMutableRawPointer.init) } } extension OpaquePointer { init(_ ptr: OpaquePointer) { self = ptr } static func make(optional ptr: OpaquePointer?) -> OpaquePointer? { return ptr.map(OpaquePointer.init) } static func make(optional ptr: UnsafeMutableRawPointer?) -> OpaquePointer? { return ptr.map(OpaquePointer.init) } static func make(optional ptr: UnsafeMutablePointer?) -> OpaquePointer? { return ptr.map(OpaquePointer.init) } }