<commit_before>//
//  Copyright (c) 2017 <NAME>
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom
//  the Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.
//

#if os(macOS) || os(iOS) || os(tvOS)
  import Foundation
  import SystemConfiguration

  /// **internal use only**
  class NetworkReachabilityManager {
    typealias ProducerBox = WeakBox<Producer<SCNetworkReachabilityFlags, Void>>

    static let `default` = NetworkReachabilityManager()
    let internalQueue = DispatchQueue(label: "NetworkReachabilityManager")
    var locking = makeLocking()
    var producerBoxesByHostName = [String: ProducerBox]()
    var producerBoxesByAddress = [NetworkAddress: ProducerBox]()
    var producerBoxesByAddressPair = [NetworkAddressPair: ProducerBox]()

    init() { }

    func channel(addressPair: NetworkAddressPair) -> Channel<SCNetworkReachabilityFlags, Void> {
      func fetch() -> (mustSetup: Bool, producer: Producer<SCNetworkReachabilityFlags, Void>) {
        if let producer = producerBoxesByAddressPair[addressPair]?.value {
          return (false, producer)
        } else {
          let producer = Producer<SCNetworkReachabilityFlags, Void>()
          producerBoxesByAddressPair[addressPair] = WeakBox(producer)
          return (true, producer)
        }
      }

      func makeNetworkReachability() -> SCNetworkReachability? {
        let localAddress: UnsafePointer<sockaddr>? = addressPair.localAddress?.data.withUnsafeBytes { $0 }
        let remoteAddress: UnsafePointer<sockaddr>? = addressPair.remoteAddress?.data.withUnsafeBytes { $0 }
        return SCNetworkReachabilityCreateWithAddressPair(nil, localAddress, remoteAddress)
      }

      return channel(fetch: fetch, makeNetworkReachability: makeNetworkReachability)
    }

    func channelForInternetConnection() -> Channel<SCNetworkReachabilityFlags, Void> {
      var address = sockaddr_in()
      address.sin_len = __uint8_t(MemoryLayout<sockaddr_in>.size)
      address.sin_family = sa_family_t(AF_INET)
      address.sin_port = 0
      return channel(address: NetworkAddress(sockaddr_in: &address))
    }

    func channel(address: NetworkAddress) -> Channel<SCNetworkReachabilityFlags, Void> {
      func fetch() -> (mustSetup: Bool, producer: Producer<SCNetworkReachabilityFlags, Void>) {
        if let producer = producerBoxesByAddress[address]?.value {
          return (false, producer)
        } else {
          let producer = Producer<SCNetworkReachabilityFlags, Void>()
          producerBoxesByAddress[address] = WeakBox(producer)
          return (true, producer)
        }
      }

      func makeNetworkReachability() -> SCNetworkReachability? {
        return address.data.withUnsafeBytes {
          return SCNetworkReachabilityCreateWithAddress(nil, $0)
        }
      }

      return channel(fetch: fetch, makeNetworkReachability: makeNetworkReachability)
    }

    func channel(hostName: String) -> Channel<SCNetworkReachabilityFlags, Void> {
      func fetch() -> (mustSetup: Bool, producer: Producer<SCNetworkReachabilityFlags, Void>) {
        if let producer = producerBoxesByHostName[hostName]?.value {
          return (false, producer)
        } else {
          let producer = Producer<SCNetworkReachabilityFlags, Void>()
          producerBoxesByHostName[hostName] = WeakBox(producer)
          return (true, producer)
        }
      }

      func makeNetworkReachability() -> SCNetworkReachability? {
        return hostName.withCString { SCNetworkReachabilityCreateWithName(nil, $0) }
      }

      return channel(fetch: fetch, makeNetworkReachability: makeNetworkReachability)
    }

    private func channel(
      fetch: () -> (mustSetup: Bool, producer: Producer<SCNetworkReachabilityFlags, Void>),
      makeNetworkReachability: () -> SCNetworkReachability?
      ) -> Channel<SCNetworkReachabilityFlags, Void> {
      let (mustSetup, producer): (Bool, Producer<SCNetworkReachabilityFlags, Void>) = locking.locker(fetch)

      if mustSetup {
        if let networkReachability = makeNetworkReachability() {
          setup(producer: producer, networkReachability: networkReachability)
        } else {
          producer.fail(AsyncNinjaError.networkReachabilityDetectionFailed)
        }
      }

      return producer
    }

    private func setup(
      producer: Producer<SCNetworkReachabilityFlags, Void>,
      networkReachability: SCNetworkReachability) {
      let queue = internalQueue
      queue.async {
        var flags = SCNetworkReachabilityFlags()
        guard SCNetworkReachabilityGetFlags(networkReachability, &flags)
          else {
            producer.fail(AsyncNinjaError.networkReachabilityDetectionFailed)
            return
        }

        producer.update(flags)
        let unmanagedProducerBox = Unmanaged.passRetained(WeakBox(producer))
        var context = SCNetworkReachabilityContext(
          version: 0,
          info: unmanagedProducerBox.toOpaque(),
          retain: { return UnsafeRawPointer(Unmanaged<ProducerBox>.fromOpaque($0).retain().toOpaque()) },
          release: { Unmanaged<ProducerBox>.fromOpaque($0).release() },
          copyDescription: nil)
        if SCNetworkReachabilitySetCallback(networkReachability, { (_, flags, info) in
          let unmanagedProducerBox = Unmanaged<ProducerBox>.fromOpaque(info!)
          unmanagedProducerBox.retain().takeUnretainedValue().value?.update(flags)
          unmanagedProducerBox.release()
        }, &context),
          SCNetworkReachabilitySetDispatchQueue(networkReachability, queue) {
          producer._asyncNinja_notifyFinalization {
            SCNetworkReachabilitySetCallback(networkReachability, nil, nil)
          }
        } else {
          producer.fail(AsyncNinjaError.networkReachabilityDetectionFailed)
        }

        unmanagedProducerBox.release()
      }
    }
  }

  // MARK: -

  /// Wraps sockaddr and it's derivetives into a convenient swift structure
  public struct NetworkAddress: Hashable {
    var data: Data

    /// Reference to a stored sockaddr
    public var sockaddrRef: UnsafePointer<sockaddr> {
      return data.withUnsafeBytes { (bytes: UnsafePointer<sockaddr>) -> UnsafePointer<sockaddr> in
        return bytes
      }
    }

    /// The hash value
    public var hashValue: Int { return data.hashValue }

    /// Initializes NetworkAddress with any sockaddr
    ///
    /// - Parameter sockaddr: to initialize NetworkAddress with
    public init(sockaddr: UnsafePointer<sockaddr>) {
      self.data = Data(bytes: sockaddr, count: Int(sockaddr.pointee.sa_len))
    }

    /// Initializes NetworkAddress with any sockaddr_in
    ///
    /// - Parameter sockaddr_in: to initialize NetworkAddress with
    public init(sockaddr_in: UnsafePointer<sockaddr_in>) {
      self = sockaddr_in.withMemoryRebound(to: sockaddr.self, capacity: 1) {
        NetworkAddress.init(sockaddr: $0)
      }
    }

    /// is equal operator
    public static func == (lhs: NetworkAddress, rhs: NetworkAddress) -> Bool {
      return lhs.data == rhs.data
    }
  }

  // MARK: -

  /// **internal use only**
  struct NetworkAddressPair: Hashable {
    var localAddress: NetworkAddress?
    var remoteAddress: NetworkAddress?
    var hashValue: Int { return (localAddress?.hashValue ?? 0) ^ (remoteAddress?.hashValue ?? 0) }

    static func == (lhs: NetworkAddressPair, rhs: NetworkAddressPair) -> Bool {
      return lhs.localAddress == rhs.localAddress && lhs.remoteAddress == rhs.remoteAddress
    }
  }

  // MARK: -

  extension SCNetworkReachabilityFlags: CustomStringConvertible {

    /// Commonly known description of the flags written on Swift
    public var description: String {
      var spec = [(SCNetworkReachabilityFlags, String)]()
      #if os(iOS)
        spec.append((.isWWAN, "W"))
      #endif<commit_msg>Fixing hashValue deprecation warnings<commit_after>//
//  Copyright (c) 2017 <NAME>ov
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom
//  the Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.
//

#if os(macOS) || os(iOS) || os(tvOS)
  import Foundation
  import SystemConfiguration

  /// **internal use only**
  class NetworkReachabilityManager {
    typealias ProducerBox = WeakBox<Producer<SCNetworkReachabilityFlags, Void>>

    static let `default` = NetworkReachabilityManager()
    let internalQueue = DispatchQueue(label: "NetworkReachabilityManager")
    var locking = makeLocking()
    var producerBoxesByHostName = [String: ProducerBox]()
    var producerBoxesByAddress = [NetworkAddress: ProducerBox]()
    var producerBoxesByAddressPair = [NetworkAddressPair: ProducerBox]()

    init() { }

    func channel(addressPair: NetworkAddressPair) -> Channel<SCNetworkReachabilityFlags, Void> {
      func fetch() -> (mustSetup: Bool, producer: Producer<SCNetworkReachabilityFlags, Void>) {
        if let producer = producerBoxesByAddressPair[addressPair]?.value {
          return (false, producer)
        } else {
          let producer = Producer<SCNetworkReachabilityFlags, Void>()
          producerBoxesByAddressPair[addressPair] = WeakBox(producer)
          return (true, producer)
        }
      }

      func makeNetworkReachability() -> SCNetworkReachability? {
        let localAddress: UnsafePointer<sockaddr>? = addressPair.localAddress?.data.withUnsafeBytes { $0 }
        let remoteAddress: UnsafePointer<sockaddr>? = addressPair.remoteAddress?.data.withUnsafeBytes { $0 }
        return SCNetworkReachabilityCreateWithAddressPair(nil, localAddress, remoteAddress)
      }

      return channel(fetch: fetch, makeNetworkReachability: makeNetworkReachability)
    }

    func channelForInternetConnection() -> Channel<SCNetworkReachabilityFlags, Void> {
      var address = sockaddr_in()
      address.sin_len = __uint8_t(MemoryLayout<sockaddr_in>.size)
      address.sin_family = sa_family_t(AF_INET)
      address.sin_port = 0
      return channel(address: NetworkAddress(sockaddr_in: &address))
    }

    func channel(address: NetworkAddress) -> Channel<SCNetworkReachabilityFlags, Void> {
      func fetch() -> (mustSetup: Bool, producer: Producer<SCNetworkReachabilityFlags, Void>) {
        if let producer = producerBoxesByAddress[address]?.value {
          return (false, producer)
        } else {
          let producer = Producer<SCNetworkReachabilityFlags, Void>()
          producerBoxesByAddress[address] = WeakBox(producer)
          return (true, producer)
        }
      }

      func makeNetworkReachability() -> SCNetworkReachability? {
        return address.data.withUnsafeBytes {
          return SCNetworkReachabilityCreateWithAddress(nil, $0)
        }
      }

      return channel(fetch: fetch, makeNetworkReachability: makeNetworkReachability)
    }

    func channel(hostName: String) -> Channel<SCNetworkReachabilityFlags, Void> {
      func fetch() -> (mustSetup: Bool, producer: Producer<SCNetworkReachabilityFlags, Void>) {
        if let producer = producerBoxesByHostName[hostName]?.value {
          return (false, producer)
        } else {
          let producer = Producer<SCNetworkReachabilityFlags, Void>()
          producerBoxesByHostName[hostName] = WeakBox(producer)
          return (true, producer)
        }
      }

      func makeNetworkReachability() -> SCNetworkReachability? {
        return hostName.withCString { SCNetworkReachabilityCreateWithName(nil, $0) }
      }

      return channel(fetch: fetch, makeNetworkReachability: makeNetworkReachability)
    }

    private func channel(
      fetch: () -> (mustSetup: Bool, producer: Producer<SCNetworkReachabilityFlags, Void>),
      makeNetworkReachability: () -> SCNetworkReachability?
      ) -> Channel<SCNetworkReachabilityFlags, Void> {
      let (mustSetup, producer): (Bool, Producer<SCNetworkReachabilityFlags, Void>) = locking.locker(fetch)

      if mustSetup {
        if let networkReachability = makeNetworkReachability() {
          setup(producer: producer, networkReachability: networkReachability)
        } else {
          producer.fail(AsyncNinjaError.networkReachabilityDetectionFailed)
        }
      }

      return producer
    }

    private func setup(
      producer: Producer<SCNetworkReachabilityFlags, Void>,
      networkReachability: SCNetworkReachability) {
      let queue = internalQueue
      queue.async {
        var flags = SCNetworkReachabilityFlags()
        guard SCNetworkReachabilityGetFlags(networkReachability, &flags)
          else {
            producer.fail(AsyncNinjaError.networkReachabilityDetectionFailed)
            return
        }

        producer.update(flags)
        let unmanagedProducerBox = Unmanaged.passRetained(WeakBox(producer))
        var context = SCNetworkReachabilityContext(
          version: 0,
          info: unmanagedProducerBox.toOpaque(),
          retain: { return UnsafeRawPointer(Unmanaged<ProducerBox>.fromOpaque($0).retain().toOpaque()) },
          release: { Unmanaged<ProducerBox>.fromOpaque($0).release() },
          copyDescription: nil)
        if SCNetworkReachabilitySetCallback(networkReachability, { (_, flags, info) in
          let unmanagedProducerBox = Unmanaged<ProducerBox>.fromOpaque(info!)
          unmanagedProducerBox.retain().takeUnretainedValue().value?.update(flags)
          unmanagedProducerBox.release()
        }, &context),
          SCNetworkReachabilitySetDispatchQueue(networkReachability, queue) {
          producer._asyncNinja_notifyFinalization {
            SCNetworkReachabilitySetCallback(networkReachability, nil, nil)
          }
        } else {
          producer.fail(AsyncNinjaError.networkReachabilityDetectionFailed)
        }

        unmanagedProducerBox.release()
      }
    }
  }

  // MARK: -

  /// Wraps sockaddr and it's derivetives into a convenient swift structure
  public struct NetworkAddress: Hashable {
    var data: Data

    /// Reference to a stored sockaddr
    public var sockaddrRef: UnsafePointer<sockaddr> {
      return data.withUnsafeBytes { (bytes: UnsafePointer<sockaddr>) -> UnsafePointer<sockaddr> in
        return bytes
      }
    }

    #if swift(>=4.1)
    // hashable conformance is synthesized automatically
    #else
    /// The hash value
    public var hashValue: Int { return data.hashValue }
    #endif

    /// Initializes NetworkAddress with any sockaddr
    ///
    /// - Parameter sockaddr: to initialize NetworkAddress with
    public init(sockaddr: UnsafePointer<sockaddr>) {
      self.data = Data(bytes: sockaddr, count: Int(sockaddr.pointee.sa_len))
    }

    /// Initializes NetworkAddress with any sockaddr_in
    ///
    /// - Parameter sockaddr_in: to initialize NetworkAddress with
    public init(sockaddr_in: UnsafePointer<sockaddr_in>) {
      self = sockaddr_in.withMemoryRebound(to: sockaddr.self, capacity: 1) {
        NetworkAddress.init(sockaddr: $0)
      }
    }

    /// is equal operator
    public static func == (lhs: NetworkAddress, rhs: NetworkAddress) -> Bool {
      return lhs.data == rhs.data
    }
  }

  // MARK: -

  /// **internal use only**
  struct NetworkAddressPair: Hashable {
    var localAddress: NetworkAddress?
    var remoteAddress: NetworkAddress?
    #if swift(>=4.1)
    // hashable conformance is synthesized automatically
    #else
    var hashValue: Int { return (localAddress?.hashValue ?? 0) ^ (remoteAddress?.hashValue ?? 0) }
    #endif

    static func == (lhs: NetworkAddressPair, rhs: NetworkAddressPair) -> Bool {
      return lhs.localAddress == rhs.localAddress && lhs.remoteAddress == rhs.remoteAddress
    }
  }

  // MARK: -

  extension SCNetworkReachabilityFlags: CustomStringConvertible {

    /// Commonly known description of the flags written on Swift
    public var description: String {
      var spec = [(SCNetworkReachabilityFlags, String)]()
      #if os(iOS)
        spec.append((.isWWAN, "W"))
      #endif
{'fraction_non_alphanumeric': 0.09173898343288628, 'fraction_numerical': 0.0021413276231263384, 'mean_word_length': 3.237583572110793, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1058467', 'n_tokens_mistral': 4981, 'n_tokens_neox': 4811, 'n_words': 1238}