Data bytes to sockaddr conversion in Swift 3.1

452 Views Asked by At

I am converting Data bytes to sockaddr for getting sa_family_t

In ObjC, it is as below:

NSData *     hostAddress;
- (sa_family_t)hostAddressFamily {
    sa_family_t     result;

    result = AF_UNSPEC;
    if ( (self.hostAddress != nil) && (self.hostAddress.length >= sizeof(struct sockaddr)) ) {
        result = ((const struct sockaddr *) self.hostAddress.bytes)->sa_family;
    }
    return result;
}

In swift I am trying to convert it as below:

var hostAddress:Data?

 private func hostAddressFamily() -> sa_family_t{

        var result: sa_family_t = sa_family_t(AF_UNSPEC)
        if (hostAddress != nil) && ((hostAddress?.count ?? 0) >= MemoryLayout<sockaddr>.size) {

            // Generic parameter 'ContentType' could not be inferred
            self.hostAddress!.withUnsafeBytes({ bytes in
                bytes.withMemoryRebound(to: sockaddr.self, capacity: 1, {sockBytes in
                    result = sockBytes.pointee.sa_family
                })
            })
        }

        return result
    }

Getting error : Generic parameter ‘ContentType’ could not be inferred

1

There are 1 best solutions below

0
On

Look at the signature of Data.withUnsafeBytesType:

func withUnsafeBytes<ResultType, ContentType>(_ body: (Swift.UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType

This method is generic over ResultType and ContentType, and the ContentType is used in the argument of the closure body.

What compiler is trying to say is that it does not know what type bytes is of. Generally, to fix this type of errors, you'll want to annotate the type in the closure:

data.withUnsafeBytes { (_ bytes: UnsafePointer<...>) -> Void in ... }

Also, it's unlikely you'll need to bind the memory twice since NSData is untyped, and you already specifying a type to bind it to.


Putting it all together:

func hostAddressFamily() -> sa_family_t {

  var result = sa_family_t(AF_UNSPEC)

  guard
    let hostAddress = hostAddress,
    hostAddress.count >= MemoryLayout<sockaddr>.size
  else {
    return result
  }

  hostAddress.withUnsafeBytes { (_ bytes: UnsafePointer<sockaddr>) in
    result = bytes.pointee.sa_family
  }

  return result
}