在 Swift 中包装 libcups C 库

Wrapping libcups C library in Swift

我正在尝试包装 libcups 库 https://github.com/apple/cups 以便在我的 Swift 项目中使用。

我已经尝试了 https://www.cups.org/doc/cupspm.html 中的一些示例,它们运行良好。

但是,在包装要在 Swift 项目中使用的 C 代码时,我遇到了困难。

我一直在网上搜索如何在 Swift 中包装 C 库,但一直没有太大进展。

这是C代码

#include <stdio.h>
#include <cups/cups.h>

typedef struct {
    int num_dests;
    cups_dest_t *dests;
} my_user_data_t;

int my_dest_cb(my_user_data_t *user_data, unsigned flags, cups_dest_t *dest) {
    if (flags & CUPS_DEST_FLAGS_REMOVED) {
        user_data->num_dests = cupsRemoveDest(dest->name, dest->instance, user_data->num_dests, &(user_data->dests));
    } else {
        user_data->num_dests = cupsCopyDest(dest, user_data->num_dests, &(user_data->dests));
    }
    return 1;
}

int my_get_dests(cups_ptype_t type, cups_ptype_t mask, cups_dest_t **dests) {
    my_user_data_t user_data = { 0, NULL };

    if (!cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, type, mask, (cups_dest_cb_t)my_dest_cb, &user_data)) {
        cupsFreeDests(user_data.num_dests, user_data.dests);
        *dests = NULL;
        return 0;
    } else {
        *dests = user_data.dests;
        return user_data.num_dests;
    }
}

int main(int argc, const char * argv[]) {
    cups_dest_t *dests = NULL;
    int num_dests = my_get_dests(0, 0, &dests);
    printf("Destination found: %d\n", num_dests);

    cups_dest_t *dest;
    int i;
    const char *value;

    for (i = num_dests, dest = dests; i > 0; i--, dest++) {
        if (dest->instance == NULL) {
            value = cupsGetOption("printer-info", dest->num_options, dest->options);
            printf("%s (%s)\n", dest->name, value ? value : "No description");
        }
    }
    return 0;
}

这是同样的事情,但在 Swift

let destinationsCallback: cups_dest_cb_t = { user_data, flags, dest in
    // (void *user_data, unsigned flags, cups_dest_t *dest)
    var userDataPointer = user_data!.assumingMemoryBound(to: my_user_data_t.self).pointee
    var destData = dest!.pointee

    if destData.instance != nil {
        print("\(String(cString: destData.name))/\(String(cString: destData.instance))")
    } else {
        print(String(cString: destData.name))
    }

    if flags == CUPS_DEST_FLAGS_REMOVED {
        userDataPointer.num_dests = cupsRemoveDest(destData.name, destData.instance, userDataPointer.num_dests, &(userDataPointer.dests))
    } else {
        userDataPointer.num_dests = cupsCopyDest(dest, userDataPointer.num_dests, &(userDataPointer.dests))
    }
    return 1
}

func getDestinations(type: UInt32, mask: UInt32, dests: UnsafeMutablePointer<cups_dest_t>) -> Int32 {
    var userData = my_user_data_t(num_dests: 0, dests: nil)

    if cupsEnumDests(UInt32(CUPS_DEST_FLAGS_NONE), 1000, nil, type, mask, destinationsCallback, &userData) != 1 {
        return 0
    } else {
        return userData.num_dests
    }
}

我无法将 userData 设为 return 我假设的正确值是由于我处理指针的方式所致。

如果能得到一些建议,将不胜感激。

恕我直言,在 Swift 中使用此类 C 库的最佳方式是在 Objective-C 中使用它们。然而,主要问题似乎是您没有写回对 userData 的更改,这就是为什么您总是获得初始值的原因。您需要像这样在回调中更新它

let userDataPointer = user_data!.assumingMemoryBound(to: my_user_data_t.self)
var userData = userDataPointer.pointee
...
// make some changes to userData

userDataPointer.pointee = userData

return 1

您的 C 代码与 Swift 代码之间似乎也存在一些差异,例如使用 'flags == CUPS_DEST_FLAGS_REMOVED' 检查标志,这通常是检查标志和比较结果的不正确方法当在原始代码中检查结果不为 0 时,cupsEnumDests 为 1。