Search code examples
zig

Instantiate struct that contains a non-pub type in Zig


I'm trying to instantiate a PyObject in Zig. In C a PyObject is essentially defined as:

struct _object {
    union {
       Py_ssize_t ob_refcnt;
       PY_UINT32_T ob_refcnt_split[2];
    };
    PyTypeObject *ob_type;
};
typedef struct _object PyObject;

which then Zig translates into:

const union_unnamed_11 = extern union {
    ob_refcnt: Py_ssize_t,
    ob_refcnt_split: [2]u32,
};
pub const struct__object = extern struct {
    unnamed_0: union_unnamed_11 = @import("std").mem.zeroes(union_unnamed_11),
    ob_type: [*c]PyTypeObject = @import("std").mem.zeroes([*c]PyTypeObject),
};
pub const PyObject = struct__object;

Now, what I'm trying to do is simply instantiate a PyObject, so:

const py = @cImport({
    @cInclude("Python.h");
});

var pyObject = py.PyObject{
    .unnamed_0 = py.union_unnamed_11{ .ob_refcnt = 1 },
    .ob_type = null,
};

// main fn and stuff..

but when I try to compile this I get the error:

$ zig build-exe t.zig -I /usr/include/python3.13 -I /usr/include -I /usr/include/x86_64-linux-gnu
t.zig:8:20: error: 'union_unnamed_11' is not marked 'pub'
    .unnamed_0 = py.union_unnamed_11{ .ob_refcnt = 1 },

This error of course makes sense, but I can't really change the union type union_unnamed_11. How can I get this to work? I'm using version 0.13.0 of Zig.


Solution

  • In this case the solution is to use Anonymous union literals.

    const py = @cImport({
        @cInclude("Python.h");
    });
    
    var pyObject = py.PyObject{
        .unnamed_0 = .{ .ob_refcnt = 1 },
        .ob_type = null,
    };
    
    // main fn and stuff..
    

    If the type was a struct, an Anonymous struct literal could be used instead.