2

I am trying to import a C array that is 64kb meant to be a circular buffer for a log on a device. When I attempt to access this array in Swift I am met with the error

Value of type 'logging' has no member 'data'

To attempt to answer potential questions about bridging, I am using other types from my imported C library that are defined in the same file that this mock code originates.

The code is setup as follows:

logging.h:

typedef struct _logging {
    uint8_t data[64*1024];
} logging;

In ReadLog.swift:

struct ReadLog {
    var log: logging = logging()

    func read() {
        //...Do some stuff...
        let char = log.data.0 // <- Error here 'Value of type 'logging' has no member 'data'
    }
}

Changing the size of data to 256 imported this member with no issue. (I don't know what the cutoff is).

What would be the best way to handle this?

Istafein
  • 110
  • 9

1 Answers1

4

The problem is that C arrays are imported to Swift as a tuple, and tuples have a maximal arity (see for example What is the limit (if any) to the tuple cardinality in Swift?). The current limit in Swift 5 seems to be 4096 tuple elements.

A possible workaround is to create a C helper function which returns a pointer to the C array. With the SE-0044 Import as member feature this can made to look like a Swift property.

You only have to add the following code either in the C header file where the logging structure is defined, or in the bridging header file:

// Pointer to the data elements:
__attribute__((swift_name("getter:logging.dataPtr(self:)")))
static inline const uint8_t * _Nonnull loggingDataPtr(const logging * _Nonnull log)
{
    return log->data;
}

Now you can read the log data in the Swift code via the pointer:

struct ReadLog {
    var log = logging()

    func read() {
        //...Do some stuff...
        let char = log.dataPtr[0]
    }
}

But be aware that there is no array bounds checking, you must ensure that log.dataPtr is only used with indices within the array size.

If you want to read and write to the logging structure from Swift then change the helper function to

// Pointer to the data elements:
__attribute__((swift_name("getter:logging.dataPtr(self:)")))
static inline uint8_t * _Nonnull loggingDataPtr(logging * _Nonnull log)
{
    return log->data;
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382