You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This PR makes `Test.Attachment` generic over its attachable value type. It gains conditional conformance to `Copyable` and `Sendable` depending on the attachable value and if you call `attach()` on a move-only or non-sendable attachment, will eagerly serialize the attachable value at that point (rather than during initialization.) There are a few benefits here: 1. Callers can statically know the type of the attachable value in an attachment rather than needing to always deal with an existential box; 2. We can add associated types to `Test.Attachable` that will be readily accessible in `withUnsafeBufferPointer(for:_:)` again without needing an existential; and 3. When we eventually add support for image attachments, we won't need a bunch of additional initializers or intermediate box types or what-have-you; and 4. For Embedded Swift or other environments where existentials are problematic, we can eagerly serialize all attachments and pass a consistent type (~~`Test.Attachment<[UInt8]>`~~ `Test.Attachment<Test.AnyAttachable>`) to the event handler. There are also some drawbacks: 1. Because conformance to `Copyable` and `Sendable` is conditional, we lose a bit of flexibility if you have a non-sendable `Test.Attachment` instance or whatnot; 2. We still need a lazy, type-erased attachment type that can be passed to the event handler. I played around with `Test.Attachment<Any>` but that causes as many problems as it solves. ~~We end up with `Test.Attachment<any Test.Attachable & Sendable & Copyable>` but, because that's an existential type that doesn't conform to itself, the generic parameter `AttachableValue` is not constrained to `Test.Attachable`. We only provide initializers for types that do conform though (plus the existential one internally) so in practice it's not a huge issue.~~ I replaced `any Test.Attachable & Sendable & Copyable` with a dedicated type-erasing box type, `Test.AnyAttachable`, that wraps the existential. In Embedded Swift, it wraps a `[UInt8]` instead. 3. There is some code duplication necessary (i.e. multiple implementations of `attach()` ~~and `write()`~~.) 4. Non-final classes cannot conform to `Test.Attachable`. You can work around this with a box type that's generic over the class and conforms to `Test.Attachable`: the `Test.AttachableContainer` protocol now exists to make this easier. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
0 commit comments