rougeware/swift-either
Did the world need another Swift `Either` type? No.
Automatic Conformance
This automatically conforms an instance of Either to various protocols if its Left and Right types also conform to them.
Currently, these are supported:
Equatable– Brings==and!=. WhenLeftandRightare unequal types, this considersleftto never equalright. When those types are equal, this ignores theleftness andrightness positions
Comparable– Brings<,<=,>=, and>. When the positions are unequal types, this considersleftto never be less than nor greater thanright. When those types are equal, this ignores the positions
Hashable– Allows an instance ofEitherto transparently be given the same hash as whatever value it contains
CustomStringConvertible– Provides a.descriptionfield with the same value as theEither's contained value's.descriptionfield
CustomDebugStringConvertible– Provides a.debugDescriptionfield with the same value as theEither's contained value's.debugDescriptionfield
Codable– AllowsEitherinstances to be encoded. This results in a multi-value keyed container which only ever contains one key-value pair where the key is"left"or"right", and the value is whatever the instance's value encodes to:
``json { "either": { "left": { "name": "Dax", "favoriteColor": 6765239 } } } ` or: `json { "either": { "right": 42 } } ` - Decodable – Decoding can accept raw values. Of course, serialized data like the above are still decoded exactly as described. As of version 2.0.0, this can also be used to decode just the raw value itself, without specifying "left"/"right": `json { "either": { "name": "Dax", "favoriteColor": 6765239 } } ` or: `json { "right": 42 } ``
SendableSimply declaresSendableconformance whenLeftandRightare alsoSendable
Unwrapping
Obviously you gotta eventually get a value out of this, and it offers a few approaches:
left– If theEitheris a.left, then that value is returned, elsenilright– If theEitheris a.right, then that value is returned, elsenil
When both Left and Right are the same type, then these are also available:
value– The current value, disregarding whether that value is.leftor.right*– Inspired by the semantics of dereferencing a pointer in C (and because Swift doesn't allow custom postfix!), place this before theEitherinstance for the same behavior as calling `.value:
``swift func name(_ user: Either<Person, Person>) -> String { return (*user).name } ``
Value– Since both positions are the same type, this typealias allows you to reference that type without specifically usingLeftorRight:
```swift typealias LegacyOrMigratedUser = Either<User, User>
func account(of user: LegacyOrMigratedUser) -> LegacyOrMigratedUser.Value.Account { (*user).account } ```
Mapping
This provides various approaches for mapping an Either. Generally these consider it a collection of exactly one element, similarly to how Optional is treated as a collection of exactly 0 or 1 elements.
map(left:right:)— Map both positions of thiseitherto different values/types, regardless of its current value. Only one of these callbacks is called each time this function is called (the one mapping a value), but this allows you to reuse the same call many times to map both sides depending on which one is set.
map(left:)– Map only theLeftposition of thiseitherto a different value/type. The callback is only called when thiseitheris a.left
map(right:)– Map only theRightposition. Inverse ofmap(left:)
Conversions
This allows you to convert instances of some types into Either and back:
Optional– AnyEitherwhoseLeftisVoidcan be turned into anOptional<Right>, and vice versa anyOptionalcan be turned into anEither<Void, Wrapped>. Just pass one to the initializer of the other:
``swift let either = Either<Void, String>.right("I'm valued") let optional = Optional(either) print(optional!) // Prints I'm valued ``
``swift var optional: String? = nil var either = Either<Void, _>(optional) print(either) // Prints left()`
optional = "I'm not sorry" either = .init(optional) print(either) // Prints right("I\'m not sorry") ```
Result– WhenEither'sRigthis anError, you can convert it to and from aResultsimilarly to the aboveOptionalconversions:
``swift let either = Either<Data, Error>.left(Data(base64Encoded: "SG93ZHk=")!) let result = Result(either) print(result) // Prints success(5 bytes) ``
``swift var result = Result<Data, Error>(catching: { try Data(contentsOf: URL(string: "https://example.com")!) }) var either = Either<_, Error>(result) print(either) // Prints left(1256 bytes)`
result = .init(catching: { try Data(contentsOf: URL(string: "https://fakeDomain.fakeTld")!) }) either = .init(result) print(either) // Prints right(Error Domain=NSCocoaErrorDomain Code=256 "The file couldn’t be opened." UserInfo={NSURL=https://fakeDomain.fakeTld}) ```
Package Metadata
Repository: rougeware/swift-either
Default branch: master
README: README.md