// // NodeListBuilder.swift // NodeItems // // Created by Casey Fleser on 3/2/23. // import SwiftUI @resultBuilder struct NodeListBuilder { typealias P = Node enum OneOf: P, CustomStringConvertible { typealias List = [NodeListBuilder.OneOf] case a(A) case b(B) var title : String { switch self { case .a(let node): return node.title case .b(let node): return node.title } } var headerTitle : String { switch self { case .a(let node): return node.headerTitle case .b(let node): return node.headerTitle } } @ViewBuilder var header : some View { switch self { case .a(let node): node.header case .b(let node): node.header } } @ViewBuilder var content : some View { switch self { case .a(let node): node.content case .b(let node): node.content } } var items : List? { get { switch self { case .a(let node): return node.items?.map { .a($0) } case .b(let node): return node.items?.map { .b($0) } } } set { } } var description : String { let valueDesc : String switch self { case .a(let node): valueDesc = ".a: \(String(describing: node))" case .b(let node): valueDesc = ".b: \(String(describing: node))" } return "OneOf: \(valueDesc)" } func icon(forHeader: Bool) -> some View { switch self { case .a(let node): node.icon(forHeader: forHeader) case .b(let node): node.icon(forHeader: forHeader) } } func matchedFilterOptions() -> SourceFilter.Options { switch self { case .a(let node): return node.matchedFilterOptions() case .b(let node): return node.matchedFilterOptions() } } } static func buildBlock(_ c: [C]) -> [C] { c } static func buildBlock ( _ c0: [C0], _ c1: [C1]) -> [OneOf] { [buildEither(first: c0), buildEither(second: c1)].flatMap { $0 } } static func buildBlock ( _ c0: [C0], _ c1: [C1], _ c2: [C2]) -> [OneOf, C2>] { [buildEither(first: buildBlock(c0, c1)), buildEither(second: c2)].flatMap { $0 } } static func buildBlock ( _ c0: [C0], _ c1: [C1], _ c2: [C2], _ c3: [C3]) -> [OneOf, OneOf>] { [buildEither(first: buildBlock(c0, c1)), buildEither(second: buildBlock(c2, c3))].flatMap { $0 } } static func buildBlock ( _ c0: [C0], _ c1: [C1], _ c2: [C2], _ c3: [C3], _ c4: [C4]) -> [OneOf, OneOf>, C4>] { [buildEither(first: buildBlock(c0, c1, c2, c3)), buildEither(second: c4)].flatMap { $0 } } static func buildBlock ( _ c0: [C0], _ c1: [C1], _ c2: [C2], _ c3: [C3], _ c4: [C4], _ c5: [C5]) -> [OneOf, OneOf>, OneOf>] { [buildEither(first: buildBlock(c0, c1, c2, c3)), buildEither(second: buildBlock(c4, c5))].flatMap { $0 } } static func buildBlock ( _ c0: [C0], _ c1: [C1], _ c2: [C2], _ c3: [C3], _ c4: [C4], _ c5: [C5], _ c6: [C6]) -> [OneOf, OneOf>, OneOf, C6>>] { [buildEither(first: buildBlock(c0, c1, c2, c3)), buildEither(second: buildBlock(c4, c5, c6))].flatMap { $0 } } static func buildBlock ( _ c0: [C0], _ c1: [C1], _ c2: [C2], _ c3: [C3], _ c4: [C4], _ c5: [C5], _ c6: [C6], _ c7: [C7]) -> [OneOf, OneOf>, OneOf, OneOf>>] { [buildEither(first: buildBlock(c0, c1, c2, c3)), buildEither(second: buildBlock(c4, c5, c6, c7))].flatMap { $0 } } // static func buildBlock(_ c: [C]...) -> [C] { // c.flatMap { $0 } // } // // Same type buildBlocks. This works but buildBlock(_ c: [C]...) -> [C] confuses the compiler static func buildBlock (_ c0: [C0], _ c1: [C0]) -> [C0] { [c0, c1].flatMap { $0 } } static func buildBlock (_ c0: [C0], _ c1: [C0], _ c2: [C0]) -> [C0] { [c0, c1, c2].flatMap { $0 } } static func buildEither(first c0: [C0]) -> [OneOf] { c0.map { OneOf.a($0) } } static func buildEither(second c1: [C1]) -> [OneOf] { c1.map { OneOf.b($0) } } static func buildOptional(_ c: [C]?) -> [C] { c ?? [] } static func buildArray(_ c: [[C]]) -> [C] { c.flatMap { $0 } } static func buildExpression(_ node: N) -> [N] { [node] } static func buildExpression(_ nodeList: NL) -> [NL.Element] { Array(nodeList) } static func buildExpression(_ nodeSource: NS) -> [NS.List.Element] { nodeSource.items.map({ buildExpression($0) }) ?? [] } }