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