Kyle-Ye
(Kyle)
1
Currently we can use typedef + __attribute((swift_newtype(struct))) to import a C struct as a Swift struct.
eg.
typedef struct DemoData_s {
...
} DemoData;
typedef DemoData *Demo __attribute((swift_newtype(struct)));
typedef uint32_t Demo2 __attribute((swift_newtype(struct)));

// And they will be imported as the following Swift interface
struct Demo { ... }
struct Demo2 { let rawValue: UInt32 }
I was wondering is there any compiler attribute that can mark a C API into a noncopyable struct in Swift.
struct A: ~Copyable { ... }
grynspan
(Jonathan Grynspan)
2
You could encapsulate the type in a Swift overlay: annotate the C type as swift_private (NS_REFINED_FOR_SWIFT) at its declaration, then on the Swift side write a wrapper type that's non-copyable:
struct DemoData: ~Copyable {
private var cDemoData: __DemoData_s
init(unsafeCDemoData cDemoData: consuming __DemoData_s) {
self.cDemoData = cDemoData
}
deinit {
__demo_data_destroy(cDemoData)
}
borrowing func runDemo() {
__demo_data_run(cDemoData)
}
}
Where __demo_data_destroy() and __demo_data_run() are hypothetical interfaces from C that operate on the C type and which have also been marked swift_private.
2 Likes
Kyle-Ye
(Kyle)
3
Got it. Although I prefer to annotate directly in C header via NS_SWIFT_NAME instead of adding a Swift overlay. This is indeed a more flexible way to solve my problem currently.
eg.
// Demo.h
typedef DemoData *Demo __attribute((swift_newtype(struct)));
NS_EXPORTED
REFINED_FOR_SWIFT
DemoData DemoCreate() NS_SWIFT_NAME(Demo.init());
NS_EXPORTED
REFINED_FOR_SWIFT
void DemoGetValue() NS_SWIFT_NAME(getter:Demo.value(self:));
Applying your solution to add an overlay, it would become the following code I guess.
// Demo.h
typedef DemoData *_Demo __attribute((swift_newtype(struct)));
NS_EXPORTED
REFINED_FOR_SWIFT
DemoData DemoCreate();
NS_EXPORTED
REFINED_FOR_SWIFT
int DemoGetValue();
struct Demo: ~Copyable {
private var cDemo: _Demo
init() { cDemo = __DemoCreate() }
deinit { __DemoDestory(self) }
var value: Int { __DemoGetValue(self) }
}
grynspan
(Jonathan Grynspan)
4
You can apply NS_REFINED_FOR_SWIFT to the type declaration too, so that in C it is named Demo and code can directly use it, while in Swift it is renamed __Demo and code works with the Swift wrapper instead (which appears, to calling code, to be exactly the same except Swiftier.)
2 Likes
Kyle-Ye
(Kyle)
5
Thanks for the nice catch up. 