Skip to content

Commit 384df6d

Browse files
committed
[ST-NNNN] Adjustments to image attachments in Swift Testing
1 parent 669c148 commit 384df6d

File tree

1 file changed

+162
-0
lines changed

1 file changed

+162
-0
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Adjustments to image attachments in Swift Testing
2+
3+
* Proposal: [ST-NNNN](NNNN-image-attachment-adjustments.md)
4+
* Authors: [Jonathan Grynspan](https://github.com/grynspan)
5+
* Review Manager: TBD
6+
* Status: **Awaiting review**
7+
* Implementation: [swiftlang/swift-testing#1359](https://github.com/swiftlang/swift-testing/pull/1359)
8+
* Review: ([pitch](https://forums.swift.org/...))
9+
10+
## Introduction
11+
12+
This proposal includes a small number of adjustments to the API surface of Swift
13+
Testing's image attachments feature introduced in [ST-0014](0014-image-attachments-in-swift-testing-apple-platforms.md)
14+
and [ST-0015](0015-image-attachments-in-swift-testing-windows.md).
15+
16+
## Motivation
17+
18+
These changes will help to align the platform-specific interfaces of the feature
19+
more closely.
20+
21+
## Proposed solution
22+
23+
The `AttachableAsCGImage` and `AttachableAsIWICBitmapSource` protocols are
24+
combined into a single protocol, `AttachableAsImage` with adjusted protocol
25+
requirements; a change is made to `AttachableImageFormat` to more closely
26+
align its interface between Darwin and Windows; `AttachableImageFormat` is made
27+
to conform to `Equatable` and `Hashable`; and an additional property is added to
28+
`Attachment` to query its image format.
29+
30+
## Detailed design
31+
32+
The following changes are proposed:
33+
34+
### Combining AttachableAsCGImage and AttachableAsIWICBitmapSource
35+
36+
The `AttachableAsCGImage` and `AttachableAsIWICBitmapSource` protocols are
37+
combined into a single protocol, `AttachableAsImage`.
38+
39+
These platform-specific requirements are removed:
40+
41+
```diff
42+
- var attachableCGImage: CGImage { get throws }
43+
- func copyAttachableIWICBitmapSource() throws -> UnsafeMutablePointer<IWICBitmapSource>
44+
```
45+
46+
They are replaced with a new requirement that encapsulates the image encoding
47+
operation. This requirement is implemented by the CoreGraphics and WinSDK
48+
overlays and is made publicly available for test authors who wish to declare
49+
additional conformances to this protocol for types that are not based on
50+
`CGImage` or `IWICBitmapSource`:
51+
52+
```swift
53+
public protocol AttachableAsImage {
54+
// ...
55+
56+
/// Encode a representation of this image in a given image format.
57+
///
58+
/// - Parameters:
59+
/// - imageFormat: The image format to use when encoding this image.
60+
/// - body: A function to call. A temporary buffer containing a data
61+
/// representation of this instance is passed to it.
62+
///
63+
/// - Returns: Whatever is returned by `body`.
64+
///
65+
/// - Throws: Whatever is thrown by `body`, or any error that prevented the
66+
/// creation of the buffer.
67+
///
68+
/// The testing library uses this function when saving an image as an
69+
/// attachment. The implementation should use `imageFormat` to determine what
70+
/// encoder to use.
71+
borrowing func withUnsafeBytes<R>(as imageFormat: AttachableImageFormat, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R
72+
}
73+
```
74+
75+
If a developer has an image type that should conform to `AttachableAsImage` and
76+
wraps an instance of `CGImage` or `IWICBitmapSource`, it is straightforward for
77+
them to delegate to that object. For example:
78+
79+
```swift
80+
import Testing
81+
import CoreGraphics
82+
83+
struct MyImage {
84+
var cgImage: CGImage
85+
// ...
86+
}
87+
88+
extension MyImage: AttachableAsImage {
89+
func withUnsafeBytes<R>(as imageFormat: AttachableImageFormat, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R {
90+
try cgImage.withUnsafeBytes(as: imageFormat, body)
91+
}
92+
}
93+
```
94+
95+
### Adjusting AttachableImageFormat
96+
97+
The following Apple-specific `AttachableImageFormat` initializer is renamed so
98+
that its first argument has an explicit label:
99+
100+
```diff
101+
public struct AttachableImageFormat {
102+
// ...
103+
- public init(_ contentType: UTType, encodingQuality: Float = 1.0)
104+
+ public init(contentType: UTType, encodingQuality: Float = 1.0)
105+
}
106+
```
107+
108+
This change makes the type's interface more consistent between Darwin and
109+
Windows (where it has an `init(encoderCLSID:encodingQuality:)` initializer.)
110+
111+
As well, conformance to `Equatable` and `Hashable` is added:
112+
113+
```swift
114+
extension AttachableImageFormat: Equatable, Hashable {}
115+
```
116+
117+
Conformance to `Equatable` is necessary to correctly implement the
118+
`withUnsafeBytes(as:_:)` protocol requirement mentioned above, and conformance
119+
to `Hashable` is generally useful and straightforward to implement.
120+
121+
### Adding an imageFormat property to Attachment
122+
123+
The following property is added to `Attachment` when the attachable value is an
124+
image:
125+
126+
```swift
127+
extension Attachment where AttachableValue: AttachableWrapper,
128+
AttachableValue.Wrapped: AttachableAsImage {
129+
/// The image format to use when encoding the represented image.
130+
public var imageFormat: AttachableImageFormat? { get }
131+
}
132+
```
133+
134+
## Source compatibility
135+
136+
These changes are breaking for anyone who has created a type that conforms to
137+
either `AttachableAsCGImage` or `AttachableAsIWICBitmapSource`, or anyone who
138+
has adopted `AttachableImageFormat.init(_:encodingQuality:)`.
139+
140+
This feature is new in Swift 6.3 and has not shipped to developers outside of
141+
nightly toolchain builds. As such, we feel confident that any real-world impact
142+
to developers will be both minimal and manageable.
143+
144+
## Integration with supporting tools
145+
146+
No changes.
147+
148+
## Future directions
149+
150+
N/A
151+
152+
## Alternatives considered
153+
154+
- Leaving the two protocols separate. Combining them allows us to lower more
155+
code into the main Swift Testing library and improves our ability to generate
156+
DocC documentation, while also simplifying the story for developers who want
157+
to use this feature across platforms.
158+
159+
## Acknowledgments
160+
161+
Thanks to my colleagues for their feedback on the image attachments feature and
162+
to the Swift community for putting up with the churn!

0 commit comments

Comments
 (0)