Currently I have a function that I want to call into some C API (namely, the GNUStep version of ObjC). I can currently do this easily with the following code (and it works perfectly), but I would love to make it 'swiftier', but restrictions on @convention(c) make that difficult.
//some class I used to wrap GNUStepNSObjects
class GNUStepNSObjectWrapper() {
}
public func objc_smart_getIMP<T>(object: GNUStepNSObjectWrapper, selector: String) -> T? {
let c = object_getClass(&object._nsobjptr!.pointee)
let v = class_getMethodImplementation(c, sel_getUid(selector))
let rt: T? = unsafeBitCast(v, to: T.self)
return rt
}
func frame() -> NSRect {
var imp: (@convention(c) (id, SEL) -> (NSRect))? = objc_smart_getIMP(object: self, selector: "frame")
if let rtn = imp?(&self.pointer, sel_getUid("frame")) {
return rtn
}
return .init(x: 0, y: 0, width: 0, height: 0)
}
but I would like to make a more generic version of this.
///This cannot work because ReturnType is not guaranteed to be a C type or a Pointer
public func objc_call_IMPNoArguments<ReturnType: CConstrainedType>(object: GNUStepNSObjectWrapper, selector: String) -> ReturnType {
let rt: (@convention(c) (id, SEL) -> (ReturnType))? = objc_smart_getIMP(object: object, selector: selector)
return rt!(&object._nsobjptr!.pointee, sel_getUid(selector))!
}
public func objc_call_IMP1Argument<ReturnType: CConstrainedType >(object: GNUStepNSObjectWrapper, selector: String, arg1: CConstrainedType) -> ReturnType {
let rt: (@convention(c) (id, SEL, arg1: CConstrainedType) -> (ReturnType))? = objc_smart_getIMP(object: object, selector: selector, arg1: CConstrainedType)
return rt!(&object._nsobjptr!.pointee, sel_getUid(selector))!
}
I am unaware of a way to tell the compiler to constrain the return type and the arguments to types that are accepted by @convention(c).
Is this possible any other way?
Maybe this is a case where we need a CSafeType protocol added to all imported C types? Does this already exist and I missed it?
I am certain that there are technical reasons (such as size of each of these types) that Swift can't simply ignore, regardless, if someone has a solution, I would love to hear.