diff --git a/Sources/SwiftExtended/Optional.swift b/Sources/SwiftExtended/Optional.swift index 35b6d44..c5a1f95 100644 --- a/Sources/SwiftExtended/Optional.swift +++ b/Sources/SwiftExtended/Optional.swift @@ -99,6 +99,30 @@ public extension Optional { } } +public extension Optional { + /// Combines (zips) the given value with the existing one - if any - to produce a tuple. + /// + /// The tuple is only produced when both optional values contain a value; otherwise, it returns `Optional.none`. + /// + /// ```swift + /// let credentials: Credentials? = usernameTextField + /// .text + /// .zip(with: passwordTextField.text) + /// .map { username, password in + /// Credentials(username: username, password: password) + /// } + /// ``` + /// + /// - Parameter other: The value to combine. + /// - Returns: A tuple containing the zipped values. + func zip(with other: Other?) -> (Wrapped, Other)? { + guard let self, let other else { + return nil + } + return (self, other) + } +} + public extension Optional where Wrapped: Equatable { /// Checks if the value is wrapped within the `Optional` type. /// - Parameter value: The value to search for. diff --git a/Tests/SwiftExtendedTests/OptionalTests.swift b/Tests/SwiftExtendedTests/OptionalTests.swift index e0dad07..507fb43 100644 --- a/Tests/SwiftExtendedTests/OptionalTests.swift +++ b/Tests/SwiftExtendedTests/OptionalTests.swift @@ -143,4 +143,33 @@ final class OptionalTests: XCTestCase { .contains(letterA) ) } + + func testZip() throws { + // given + let leftHandSideValue = 1 + let rightHandSideValue = "A" + + // when + let unzippedPair = try XCTUnwrap( + Optional + .some(leftHandSideValue) + .zip(with: Optional.some(rightHandSideValue)) + ) + + // then + XCTAssertEqual(leftHandSideValue, unzippedPair.0) + XCTAssertEqual(rightHandSideValue, unzippedPair.1) + + // and when + let nilDueToLeftHandSide = Optional + .none + .zip(with: Optional.some(rightHandSideValue)) + let nilDueToRightHandSide = Optional + .some(leftHandSideValue) + .zip(with: Optional.none) + + // then + XCTAssertNil(nilDueToLeftHandSide) + XCTAssertNil(nilDueToRightHandSide) + } }