Supporting Span in packages

As we approach the release of Swift 6.2, I would like to provide some information about how to support Span in packages. As you may have noticed in the pre-released compilers, Span and its related types are being added to the standard library with backdeployment support for Darwin-based platforms. While the types are backdeployable, there is a limit to how far back they can be back-deployed, so that there are restrictions both on the compiler and on the deployment.

The Span family of types includes: Span<T>, RawSpan, MutableSpan<T>, MutableRawSpan, OutputSpan<T> and OutputRawSpan. Note that UTF8Span does not have back-deployment support.

To use APIs involving the Span family of types, you must use a Swift 6.2 compiler. This is the only requirement for platforms without a stable ABI, such as Linux, Windows, and embedded targets.

On platforms with a stable ABI, API using the Span family of types can execute on a wide range of OS versions, starting with macOS 10.14.4, iOS 12.2, watchOS 5.2, tvOS 12.2, and visionOS 1.0.

These restrictions can be accommodated with some annotations, namely conditional compilation and availability annotations. Here is an example declaration for extensions to ByteBuffer:

extension ByteBuffer {
#if compiler(>=6.2)
    @available(macOS 10.14.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *)
    public var someBytes: RawSpan {
        @_lifetime(self)
        borrowing get { /* ... */ }
    }

    @available(macOS 10.14.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *)
    public init(copying bytes: RawSpan) { /* ... */ }
#endif
}
11 Likes

OutputSpan appears as appleOS 26+, so not backdeployed as far as I can tell. There are no docs for OutputRawSpan, so difficult to tell its deployment.

How can I use backdeployed span types? I cannot figure out how to create a value of these span types targeting macOS 15 and earlier.

Such a bummer utf8Span didn’t make it for back-deployment :frowning:

I’ve been trying to optimize some ip[v4-v6]-string-parsing logic that takes into account if a string is not in proper ASCII but after an IDNA conversion would result in a proper ASCII ip-string, and I’ve noticed a decent amount of unnecessary checks that slowdown the whole process without gaining the implementation anything useful. For example a lot of String.Index bounds checks when using unicodeScalars view, which are no good for me considering I already have a decent amount of tests with all edge cases I could think of, partially to make sure my code doesn’t try to access out of bounds indices. Also I’ve noticed some other relatively low-performance stuff there as well, like string.distance, or that iterating over string.indices has very bad performance since it uses DefaultIndices instead of some specialized type that checks bounds once and proceeds to issue indices without bounds checks the next times. It’s also pretty annoying that `String.Index` stuff have 0 facilities to say “I swear I know this is fine, just don’t do any bounds checks“.

For some numbers, the most optimized version of the IPv4 implementation I could put together still resulted in 14.4% of the performance to go to _StringGuts.validateInclusiveScalarIndex. I believe at least 10% of this could have been avoided if I could tell ask for less bounds checks.

Side note - I’m dropping the IDNA-compliance for those initializers considering long story short, it’s overkill, results in some performance hit, and is still possible to do adequately through DomainName even without these dedicated initializers.

Anyway I don’t think we should discuss those in this thread. I’m not sure if I have the time to put a proper thread about those together. Specially since we have utf8Span now which solves most of the issues.

Which brings me to the point: utf8Span is basically what I was missing when trying to make things work with the UnicodeScalarView. I wasn’t aware utf8Span goes above basic “utf8“ stuff and provides other utilities such as makeUnicodeScalarIterator(), and checkForNFC().
I was delighted to find out that’s the case. But then I remembered that utf8Span was not part of the back-deployed stuff and I now have to choose between requiring a higher macos version for macos users (for those specific initializers), or not using utf8Span.

So yeah. This was all to say I wish utf8Span did also make it to the back-deployments :frowning:

2 Likes