ST-0017: Consolidate Swift Testing’s image attachments API across platforms

Hello Swift Community!

The review of ST-0017 “Consolidate Swift Testing's image attachments API across platforms” begins now and runs through Thursday October 30, 2025. The proposal is available here:

swift-evolution/proposals/testing/0017-image-attachment-consolidation.md at main · swiftlang/swift-evolution · GitHub

Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to the review manager. When messaging the review manager directly, please keep the proposal link at the top of the message.

Note: This is a shorter review period because this proposal is consolidating & fixing up the differences between ST-0014 and ST-0015 before the next release of Swift goes out and turns this proposal into an ABI and API breaking change.

Trying it out

To try this feature out, add a dependency to the jgrynspan/image-attachment-adjustments branch of swift-testing to your project:

...
dependencies: [
  ...
  .package(
    url: "https://github.com/swiftlang/swift-testing.git",
    branch: "jgrynspan/image-attachment-adjustments"
  ),
]

Then, add a target dependency to your test target:

.testTarget(
  ...
  dependencies: [
    ...
    .product(name: "Testing", package: "swift-testing"),
    .product(name: "_Testing_ExperimentalImageAttachments", package: "swift-testing"),
  ]
)

Finally, import Swift Testing & the appropriate overlay(s) to any source file that will attach an image to a test:

import X
import _Testing_X

Where X is the module name of the image type you're using:

Image Type Module Name
CGImage CoreGraphics
CIImage CoreImage
NSImage AppKit
UIImage UIKit

On Windows, X needs to be WinSDK (as in: import _Testing_WinSDK).

Note: This extra product dependency and extra import statement are a side effect of how packages are built. They will not be required in the final implementation of this feature.

What goes into a review?

The goal of the review process is to improve the proposal under review
through constructive criticism and, eventually, determine the direction of
Swift. When writing your review, here are some questions you might want to
answer in your review:

  • What is your evaluation of the proposal?

  • Is the problem being addressed significant enough to warrant a change to Swift?

  • Does this proposal fit well with the feel and direction of Swift?

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

swift-evolution/process.md at main · swiftlang/swift-evolution · GitHub

Thank you for contributing to Swift!

Rachel Brindle

Review Manager

5 Likes

Instead of using unsafe pointers in the new protocol requirements can we use RawSpan instead?

1 Like

No, we cannot use RawSpan here:

  • If we were using RawSpan, the signature of the protocol requirement would presumably be: func bytes(as imageFormat: AttachableImageFormat) throws -> RawSpan, however you cannot return a RawSpan from a function (yet).
  • If you could return RawSpan from a function, you would have no way to declare its lifetime because it is derived from some value that is created inside the function and is destroyed when it returns.
  • The alternative signature would be func withBytes<R>(as imageFormat: AttachableImageFormat, _ body: (borrowing RawSpan) throws -> R) throws -> R. This is not idiomatic Swift (insofar as there are no examples of a with function yielding a span that I can find in the stdlib).

Edit: I double-checked, and while one of the specific RawSpans we'd need here is back-deployed to macOS 10.14.4, iOS 12.2, etc., other ones we'd need are not back-deployed and require macOS/iOS 26. Since we do want this feature to be available on earlier Apple platforms, we cannot adopt RawSpan in Swift Testing's attachments feature.

2 Likes

Would this be valuable to add as an Alternatives Considered section in the proposal?

1 Like

I’m in favor of this change, as the previous approach of platform-specific protocol conformances and extensions wasn’t scalable long term as Swift starts to adopt additional platforms like Android.

This makes it much more straightforward as a library author to understand and conform to work for platforms I need to support with my tooling.

I followed this from the pitch, and was happy to see this addition to make the protocols more structured and somewhat hierarchical, like the rest of the Swift Standard Library is designed, so that SwiftTesting is much less bespoke, with proper abstractions.

2 Likes

I can do that, sure. RawSpan was previously discussed in ST-0009 when we introduced attachments, but I realize that's ancient history (and the discussion then predates any back-deployment of spans.) So it makes sense to discuss it here too.

Edit: We're tracking RawSpan adoption in the attachments feature here.

1 Like

+1 to the proposal from my perspective.

I agree it would be great for this, and for all usages of unsafe buffer pointers in the Attachments API surface, to adopt RawSpan. @grynspan reminded me that he noted that as a future direction in ST-0009: Attachments. Since it can't be accomplished today due to the reasons mentioned above, but there's a general desire and intention to eventually do it once possible, I'd suggest this be noted as a future direction rather than an alternative considered in this proposal. (It's a subtle difference but I think that would help convey the intention better.)

1 Like

Will it ever be possible to return a RawSpan, given @grynspan’s point about lifetimes?

If that will always be a blocker, then would it make sense for this proposal to blaze the withBytes { (span: borrowing RawSpan) in } trail? It doesn’t sound like there are any technical blockers to that approach in the current implementation of RawSpan/noncopyable types.

Edit: Spoke to Jonathan offline, it sounds like that’s not a viable approach at this time.

1 Like

For future reference, I have started working on adopting RawSpan on a branch, although these changes are out of scope for this proposal.

Edit: Opened [ST-0017] Add a future direction to move to `RawSpan`. by grynspan · Pull Request #3013 · swiftlang/swift-evolution · GitHub

4 Likes

This proposal has been accepted. Thanks for everyone who participated in review!