Allow coercion of `Optional<T>` to `Optional<UnsafePointer<T>>`

There exist C APIs which have functions that take pointers as arguments, where a null pointer indicates that the argument has no value. Here is an example from an API I am working with:

C header
/*
 * XPLMFindNavAid
 * 
 * This routine provides a number of searching capabilities for the nav
 * database. XPLMFindNavAid will search through every navaid whose type is
 * within inType (multiple types may be added together) and return any navaids
 * found based on the following rules:
 * 
 * * If inLat and inLon are not NULL, the navaid nearest to that lat/lon will
 *   be returned, otherwise the last navaid found will be returned.
 * 
 * * If inFrequency is not NULL, then any navaids considered must match this
 *   frequency.  Note that this will screen out radio beacons that do not have
 *   frequency data published (like inner markers) but not fixes and airports.
 * 
 * * If inNameFragment is not NULL, only navaids that contain the fragment in
 *   their name will be returned.
 * 
 * * If inIDFragment is not NULL, only navaids that contain the fragment in
 *   their IDs will be returned.
 * 
 * This routine provides a simple way to do a number of useful searches:
 * * Find the nearest navaid on this frequency.
 * * Find the nearest airport.
 * * Find the VOR whose ID is "KBOS".
 * * Find the nearest airport whose name contains "Chicago".
 *
 */
XPLM_API XPLMNavRef XPLMFindNavAid(
                         const char *         inNameFragment,         /* Can be NULL */
                         const char *         inIDFragment,           /* Can be NULL */
                         float *              inLat,                  /* Can be NULL */
                         float *              inLon,                  /* Can be NULL */
                         int *                inFrequency,            /* Can be NULL */
                         XPLMNavType          inType);

In these cases, my translation into a more idiomatic API in Swift takes an optional keyword argument, defaulting to nil. I would like to be able to use the normal syntactic sugar of &it, so that when, for example with lat, if it's nil, then the C API gets NULL, but if it's not nil, then the C API gets a pointer to it.

Currently, this is considered an error -- T? cannot be coerced to a UnsafeMutablePointer<T>?. This results in some very clumsy code:

Clumsy Swift code
// In one file
internal func withModulatedOptional<T, Res>(
    mut it: inout T?,
    _ clz: (UnsafeMutablePointer<T>?) -> Res
) -> Res {
    if var it {
        return clz(&it)
    } else {
        return clz(nil)
    }
}

// In the static function to find a navaid:
let ref = withModulatedOptional(mut: &lat) { (lat) in
    withModulatedOptional(mut: &lon) { (lon) in
        withModulatedOptional(mut: &frequency) { (frequency) in
            XPLMFindNavAid(
                nameFragment,
                identFragment,
                lat,
                lon,
                frequency,
                type.xplm
            )
        }
    }
}

This really isn't ideal. I don't think it's too major a change to do this, and it would get rid of those nested closures and the weird wrapper function.

2 Likes