How to bridge between CoreFoundation and SwiftFoundation on Linux?


#1

Hi all,

When working with CoreFoundation objects (e.g. CFReadStream, CFWriteStream) it isn't immediately obvious to me how to bridge them to SwiftFoundation counterparts (InputStream / OutputStream).

The following works on OSX, but doesn't work on Linux;

    let readStream: CFReadStream = ...
    readStream as InputStream
    // error: cannot convert value of type 'CFReadStream' to expected argument type 'InputStream'

In some other places I need to bridge a String to a CFString, the following works on OSX, but doesn't work on Linux;

    let string: String = ...
    string as CFString
    // error: error: 'String' is not convertible to 'CFString'; did you mean to use 'as!' to force downcast?

Thanks.

···

--
-Bouke


(Jens Alfke) #2

What implementation of CF are you using on Linux? OpenStep?

The bridging between Swift and Obj-C Foundation classes is only implemented on Apple platforms. It’s not part of the open source release. The plan is to implement classes like InputStream in native Swift as part of the standard library; that work is in progress.

—Jens

···

On Sep 20, 2016, at 9:38 PM, Bouke Haarsma via swift-users <swift-users@swift.org> wrote:

When working with CoreFoundation objects (e.g. CFReadStream, CFWriteStream) it isn't immediately obvious to me how to bridge them to SwiftFoundation counterparts (InputStream / OutputStream).

The following works on OSX, but doesn't work on Linux;


#3

The code is for another project. I’m trying to build a (partial) Swift implementation of NetService. See also https://github.com/Bouke/NetService/tree/linux.

Apparently that protocol is EOL;

···

// slated for removal, these are the swift-corelibs-only variant of the _ObjectiveCBridgeable
internal protocol _CFBridgeable {
    associatedtype CFType
    var _cfObject: CFType { get }
}


Bouke

On 21 Sep 2016, at 21:56, Will Stanton <willstanton1@yahoo.com> wrote:

Hello Bouke,

Is that code you’re working on within SwiftFoundation or for another project?

I believe _cfObject can bridge String to CFString within SwiftFoundation (but it’s an internal property), for example in NSDateFormatter.swift:
String -> CFString
_setFormatterAttribute(formatter, attributeName: kCFDateFormatterAMSymbol, value: _amSymbol?._cfObject)
CFString -> String
(CFDateFormatterCopyProperty(_cfObject, kCFDateFormatterAMSymbol) as! NSString)._swiftObject

Within SwiftFoundation, it seems CFReadStream+CFWriteStream do not have associated CFTypes. That may be because their implementations just started, but I am not sure what the plan is with those classes and `protocol _CFBridgeable`.

Regards,
Will Stanton

On Sep 21, 2016, at 12:38 AM, Bouke Haarsma via swift-users <swift-users@swift.org> wrote:

Hi all,

When working with CoreFoundation objects (e.g. CFReadStream, CFWriteStream) it isn't immediately obvious to me how to bridge them to SwiftFoundation counterparts (InputStream / OutputStream).


#4

The one that comes with SwiftFoundation (https://github.com/apple/swift-corelibs-foundation/tree/master/CoreFoundation).

I think it should be a bug that CFReadStream cannot be bridged to (NS)InputStream, as otherwise there’s no way to intertwine Sockets (CFSockets) with SwiftFoundation. As the implementation already uses a CFReadStream internally (https://github.com/apple/swift-corelibs-foundation/blob/d3872cb094124d5dd189839505ae73e2fa717cfd/Foundation/NSStream.swift#L122), it would be a matter of adding an initializer. However the value is private, so adding the initializer cannot be done from an extension.

···


Bouke

On 21 Sep 2016, at 21:22, Jens Alfke <jens@mooseyard.com> wrote:

On Sep 20, 2016, at 9:38 PM, Bouke Haarsma via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

When working with CoreFoundation objects (e.g. CFReadStream, CFWriteStream) it isn't immediately obvious to me how to bridge them to SwiftFoundation counterparts (InputStream / OutputStream).

The following works on OSX, but doesn't work on Linux;

What implementation of CF are you using on Linux? OpenStep?

The bridging between Swift and Obj-C Foundation classes is only implemented on Apple platforms. It’s not part of the open source release. The plan is to implement classes like InputStream in native Swift as part of the standard library; that work is in progress.

—Jens


(Philippe Hausler) #5

I would suggest that the way to do it is to follow the NSString/NSNumber approach used in swift-corelibs-foundation where the structural size is equivalent.

the layout would roughly look like:

open class InputStream : Stream {
    typealias CFType = CFReadStream
    // This layout MUST be the same as CFReadStream so that they are bridgeable
    private var _base = _CFInfo(typeID: CFReadStreamGetTypeID())
    private var _flags: CFOptionFlags = 0
    private var _error: UnsafeMutableRawPointer? = nil
    private var _info: UnsafeMutableRawPointer? = nil
    private var _callBacks: UnsafeMutableRawPointer? = nil
#if os(OSX) || os(iOS)
    private var _lock = pthread_mutex_t()
#elseif os(Linux)
    private var _lock = Int32(0)
#endif
    private var _previousRunloopsAndModes: UnsafeMutableRawPointer? = nil
#if DEPLOYMENT_ENABLE_LIBDISPATCH
    private var _queue: UnsafeMutableRawPointer? = nil
#endif

    internal var _cfObject: CFType {
        return unsafeBitCast(self, to: CFType.self)
    }

    ...
}

This would ensure the memory size of the allocation of InputStream would be the same as CFReadStream.

These two calls would then need to be un-commented in NSSwiftRuntime.swift

// _CFRuntimeBridgeTypeToClass(CFReadStreamGetTypeID(), unsafeBitCast(InputStream.self, UnsafeRawPointer.self))
// _CFRuntimeBridgeTypeToClass(CFWriteStreamGetTypeID(), unsafeBitCast(OutputStream.self, UnsafeRawPointer.self))

and __CFSwiftBridge would need entries for calling out to swift for subclassers.

···

On Sep 21, 2016, at 1:03 PM, Bouke Haarsma via swift-users <swift-users@swift.org> wrote:

The one that comes with SwiftFoundation (https://github.com/apple/swift-corelibs-foundation/tree/master/CoreFoundation).

I think it should be a bug that CFReadStream cannot be bridged to (NS)InputStream, as otherwise there’s no way to intertwine Sockets (CFSockets) with SwiftFoundation. As the implementation already uses a CFReadStream internally (https://github.com/apple/swift-corelibs-foundation/blob/d3872cb094124d5dd189839505ae73e2fa717cfd/Foundation/NSStream.swift#L122), it would be a matter of adding an initializer. However the value is private, so adding the initializer cannot be done from an extension.


Bouke

On 21 Sep 2016, at 21:22, Jens Alfke <jens@mooseyard.com <mailto:jens@mooseyard.com>> wrote:

On Sep 20, 2016, at 9:38 PM, Bouke Haarsma via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

When working with CoreFoundation objects (e.g. CFReadStream, CFWriteStream) it isn't immediately obvious to me how to bridge them to SwiftFoundation counterparts (InputStream / OutputStream).

The following works on OSX, but doesn't work on Linux;

What implementation of CF are you using on Linux? OpenStep?

The bridging between Swift and Obj-C Foundation classes is only implemented on Apple platforms. It’s not part of the open source release. The plan is to implement classes like InputStream in native Swift as part of the standard library; that work is in progress.

—Jens

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users