-
-
Save wotjd/80f19dbc67f0e54c24daed73378eb264 to your computer and use it in GitHub Desktop.
ArrayBuilder - Swift ~~FunctionBuilder~~ ResultBuilder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@resultBuilder | |
public struct ArrayBuilder<Element> { | |
public static func buildPartialBlock(first: Element?) -> [Element] { first.map { [$0] } ?? [] } | |
public static func buildPartialBlock(first: [Element]?) -> [Element] { first ?? [] } | |
public static func buildPartialBlock(first: [Element?]?) -> [Element] { (first ?? []).compactMap { $0 } } | |
public static func buildPartialBlock(accumulated: [Element], next: Element?) -> [Element] { accumulated + (next.map { [$0] } ?? []) } | |
public static func buildPartialBlock(accumulated: [Element], next: [Element]?) -> [Element] { accumulated + (next ?? []) } | |
public static func buildPartialBlock(accumulated: [Element], next: [Element?]?) -> [Element] { accumulated + (next ?? []).compactMap { $0 } } | |
// Empty Case | |
public static func buildBlock() -> [Element] { [] } | |
// If/Else | |
public static func buildEither(first: [Element]) -> [Element] { first } | |
public static func buildEither(second: [Element]) -> [Element] { second } | |
// Just ifs | |
public static func buildIf(_ element: [Element]?) -> [Element] { element ?? [] } | |
// fatalError() | |
public static func buildPartialBlock(first: Never) -> [Element] {} | |
} | |
// MARK: - Array.init(builder:) | |
public extension Array { | |
init(@ArrayBuilder<Element> builder: () -> [Element]) { | |
self.init(builder()) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import XCTest | |
final class ArrayBuilderTests: XCTestCase { | |
let bool = false | |
func testExample() throws { | |
expect(["hello"]) { | |
"hello" | |
} | |
expect(["hello", "world"]) { | |
"hello" | |
"world" | |
} | |
expect(["world"]) { | |
if bool { | |
"hello" | |
} else { | |
"world" | |
} | |
} | |
expect(["world", "world"]) { | |
if bool { | |
"hello" | |
"hello" | |
} else { | |
"world" | |
"world" | |
} | |
} | |
expect(["world", "world"]) { | |
if bool { | |
"hello" | |
"hello" | |
} else if !bool { | |
"world" | |
"world" | |
} else { | |
"" | |
} | |
} | |
expect([]) { | |
if bool { | |
"hello" | |
} | |
} | |
expect(["hello"]) { | |
if !bool { | |
if !bool { | |
"hello" | |
} | |
} | |
} | |
expect(["world"]) { | |
if bool { | |
"hello" | |
} | |
if !bool { | |
"world" | |
} | |
} | |
expect(["foo", "world"]) { // [String] or [[String]] ?? | |
"foo" // :String | |
if bool { | |
"hello" // :String | |
} else { | |
"world" // :String | |
} // :[String] | |
} | |
expect(["foo", "world"]) { | |
["foo"] | |
if bool { | |
"hello" | |
} else { | |
"world" | |
} | |
} | |
expect(["world1", "world2"]) { | |
if bool { | |
"hello1" | |
} else { | |
"world1" | |
} | |
if bool { | |
"hello2" | |
} else { | |
"world2" | |
} | |
} | |
//expect(["hello"]) { | |
// guard bool else { | |
// return [] | |
// } | |
// "bar" | |
// "baz" | |
//} | |
expect([]) { | |
} | |
func fatal() { | |
expect(["hello"]) { | |
fatalError() | |
} | |
expect(["hello"]) { | |
if bool { | |
fatalError() | |
} | |
} | |
expect(["hello"]) { | |
if bool { | |
fatalError() | |
} else { | |
fatalError() | |
} | |
} | |
// This works, just has a warning | |
// _ = expect(["hello"]) { | |
// if bool { | |
// "hello" | |
// fatalError() | |
// } else { | |
// "world" | |
// fatalError() | |
// } | |
// } | |
} | |
//expect(["hello"]) { | |
// for str in ["hello", "world"] { | |
// str | |
// } | |
//} | |
expect(["hello", "world"]) { | |
["hello", "world"].map { str in | |
str | |
} | |
} | |
expect(["world"]) { | |
switch bool { | |
case true: "hello" | |
case false: "world" | |
} | |
} | |
} | |
func test2() { | |
XCTAssertEqual(["hello"], Array<String>(builder: { | |
"hello" | |
})) | |
XCTAssertEqual(["hello", "world"], Array<String>(builder: { | |
"hello" | |
"world" | |
})) | |
XCTAssertEqual(["world"], Array<String>(builder: { | |
if bool { | |
"hello" | |
} else { | |
"world" | |
} | |
})) | |
XCTAssertEqual([], Array<String>(builder: { | |
if bool { | |
"hello" | |
} | |
})) | |
XCTAssertEqual(["world", "world"], Array<String>(builder: { | |
"world" | |
"world" | |
if bool { | |
"hello" | |
"optional" | |
} | |
})) | |
XCTAssertEqual(["world", "world"], Array<String>(builder: { | |
"world" | |
if bool { | |
"hello" | |
"optional" | |
} | |
"world" | |
})) | |
XCTAssertEqual(["world", "world"], Array<String>(builder: { | |
if bool { | |
"hello" | |
"optional" | |
} | |
"world" | |
"world" | |
})) | |
XCTAssertEqual(["world", "world"], Array<String>(builder: { | |
if bool { | |
"hello" | |
"optional" | |
} | |
if bool { | |
"hello" | |
"optional" | |
} | |
"world" | |
"world" | |
})) | |
XCTAssertEqual(["world"], Array<String>(builder: { | |
["world"] | |
if bool { | |
"hello" | |
"optional" | |
} | |
})) | |
} | |
func expect(_ expected: [String], @ArrayBuilder<String> block: () -> [String]) { | |
XCTAssertEqual(expected, block()) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment