This change adds conditional `Sendable` conformance to all
property wrapper types when their `Value` is `Sendable`, enabling
commands to be used in concurrent contexts. Some notes on
the implementation:
* Fix flag exclusivity issues
This derives the `hasUpdated` check from the parsed values data type,
rather than storing it in the closure (which breaks sendability) or
passing it through the closure invocation (which wasn't finished
enough to actually work).
* Mark all `transform` methods as `@Sendable`
This allows for a stronger, compiler-supported guarantee of
sendability when a compound `ParsableArguments` or `ParsableCommand`
type is marked `Sendable`. Most transformations shouldn't be a
problem, since the general case is that these are pure string ->
value transformations.
In cases where making such a transformation sendable is impossible,
an author can always change the property to be just a string and
perform the transformation within the context of the command's
execution, in either the `run()` or `validate()` methods.
* Add `@preconcurrency` to Sendable closure APIs
This adds the `@preconcurrency` attribute to all public APIs that
have changed to take a `@Sendable` closure. This will ease the
migration path for sendable adoption for ArgumentParser users, since
a warning will only appear for using these APIs (like the `transform`
parameter in an @Option or @Argument) once they've turned on strict
concurrency checking.
I'm also backing out changes that avoided those warnings in the tests
and examples, since in most cases those warnings are spurious;
unapplied functions don't capture state. See
https://forums.swift.org/t/pitch-inferring-sendable-for-methods-and-key-path-literals/68011
for more on this and hopefully an upcoming fix for these issues.
* Raise minimum Swift version to 5.7
In order to provide `@preconcurrency` support, the package needs to
have a minimum Swift requirement of 5.7. This makes that change and
updates the README to indicate this for the next version.
Fixes “Internal error. Invalid state while parsing command-line arguments.” that is encountered when an unparsed value is optional.
Root causes:
- `ParsedArgumentsContainer.decodeNil` returns false for optional values because it only does a `!contains(key)` check. This should instead return nil if the value of the element is nil.
- The decoder did not know about unparsed input origins that and would result in unexpected behavior when decoding nil default values.
- The `value` of `Mirror.Child` is defined as `Any` but this is confusing because the value could be `Optional<Any>` which is not equal to `nil` even when the `Optional` case is `.none`.
Co-authored-by: Mike <mike.wermuth@icloud.com>
We're newly able to decode actual optional types due to allowing
unparsed variable properties. "Normal" optional values are still
wrapped in non-optional property wrappers, so ArgumentDecoder didn't
need to handle optional values until now. Fixes#285
* Convert some linear operations to constant time
* Temporary test command for performance testing
* Improve SplitArguments docs
* Re-enable split arguments unit test
* Restore repeat example
Previously, we were only storing full-decoded ParsableCommand instances
for subcommands to pick up with the @OptionGroup() wrapper. This change
stores all decoded @OptionGroup() values as well, so that they can be
shared from super- to subcommand.