Converting Opaque** to [Opaque]

Not C expert here, so feel free to correct me if I'm wrong

I have a list of pointers to opaque types

GLFWAPI GLFWmonitor** glfwGetMonitors(int* count);

where:

typedef struct GLFWmonitor GLFWmonitor;

which under Swift is of type:

UnsafeMutablePointer<UnsafeMutablePointer<GLFWmonitor>?>!

Writing a swift wrapper, this is what I'd do:

    struct Monitor {
    }
    var monitors: [Monitor] {
        var count: Int32 = 0
        let monitors = glfwGetMonitors(&count)!
        Array(UnsafeBufferPointer(start: monitors[0]!, count: count))
    }

but I get:

error: cannot convert value of type 'OpaquePointer?' to expected argument type 'UnsafePointer<_>?'

How can I solve? Am I doing right?

Shall opaque types be represented by structs?

which under Swift is of type:

Are you sure? The way that Swift imports pointers to C structs depends on how the struct is declared:

  • For a standard struct, you get UnsafeMutablePointer<xxx>

  • For an incomplete struct [1], you get OpaquePointer

When I put your C declarations into a test project, the Swift declaration for glfwGetMonitors comes back as:

func glfwGetMonitors(_ count: UnsafeMutablePointer<Int32>!) -> UnsafeMutablePointer<OpaquePointer?>!

The fact that you’re getting an error that includes OpaquePointer suggests that this is happening to you as well.

So, is GLFWmonitor an incomplete struct?

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

[1] Incomplete structs are an oddity in C where you can declare a type like this:

struct Foo;

This says “there is a struct Foo but we don’t know anything about its contents yet”. This is commonly used for opaque ‘handles’ to objects. The C API is built in terms of pointers to such structs, allowing the implementer to keep all the details private.

For example, macOS has this declaration:

typedef const struct AuthorizationOpaqueRef * AuthorizationRef;

and then has a whole bunch of functions that operate on the resulting AuthorizationRef:

OSStatus AuthorizationCreate(… AuthorizationRef * authorization);
OSStatus AuthorizationCopyRights(AuthorizationRef authorization …);
OSStatus AuthorizationFree(AuthorizationRef authorization …);

allowing apps to manipulate these authorisation references without knowing about any of the internal details.

4 Likes

Unless CLion is deceiving me, 100% sure

I think is just an opaque type (but as I said, not an expert, so take with a ton of salt)

Code and docs

You are saying the same thing. Where you say "opaque type", @eskimo says "incomplete struct", but you both mean the same thing: a C structure whose name you know but whose size you do not.

In this case, the public header files for GLFW seem not to include a definition for struct GLFWmonitor, which means that by definition it is incomplete or opaque. The type exists, but you don't know anything about its size. In Swift, pointers to such a type are aways OpaquePointer (see Opaque Pointers in Swift for a discussion of the pros and cons of this).

I don't know why CLion is getting this wrong, but wherever it is getting the type definitions from it has access to the actual structure definition and so is concluding the wrong thing about the type. The variable monitors therefore has the type UnsafeMutablePointer<OpaquePointer?>!, as @eskimo has noted.

Answering this more specifically: no, they cannot be. structs have size, they have layout, they can be copied around. Opaque types have no known size, no known layout, they cannot be held.

1 Like

Uh, ok, thanks!

I'll open an issue on their bug tracking then

I changed strategy and using typealias now:

    typealias Monitor = OpaquePointer // using this instead of GLFWmonitor because otherwise I get
                                      // > error: use of undeclared type 'GLFWmonitor'
    var monitors: [Monitor] {
        var count: Int32 = 0
        let monitors = glfwGetMonitors(&count)!
        var res: [Monitor] = []
        for i in 0..<Int(count) {
            res += monitors[i]! as Monitor
        }
        return res
    }