-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bundle の実装 #50
Comments
プロパティラッパーの仕様では、多分無理では? |
result builder を使う方法がいいかもしれません。 struct Transform: Bundle {
var builder: some BundleElements {
// いい感じにつくれるようにする
BundleBuilder {
Position()
ZPosition()
}
}
} |
こんな感じの API をまず思いつきました。 struct Transform: Bundle {
var body: some BuilderElement {
bundleBuilder {
component(Pos())
component(ZPos())
}
}
} struct Sprite: Bundle {
var body: some BuilderElement {
bundleBuilder {
component(Size())
component(Texture())
bundle(Transform())
}
}
}
この API の内部についての補足二分木ノードまず、二分木のノードの定義です。 protocol BuilderElement {
}
struct End<C: Component>: BuilderElement {
let initialValue: C
}
struct Link<Previous: BuilderElement, Behind: BuilderElement>: BuilderElement {
let previous: Previous
let behind: Behind
} bundle builder続いて
まずは result builder です。 @resultBuilder
struct BundleBuilder {
static func buildBlock<T>(_ value: T) -> T {
value
}
static func buildBlock<P0, P1>(_ p0: P0, _ p1: P1) -> Link<P0, P1> {
Link(previous: p0, behind: p1)
}
static func buildBlock<P0, P1, P2>(_ p0: P0, _ p1: P1, _ p2: P2) -> Link<P0, Link<P1, P2>> {
Link(previous: p0, behind: Link(previous: p1, behind: p2))
}
static func buildBlock<P0, P1, P2, P3>(_ p0: P0, _ p1: P1, _ p2: P2, _ p3: P3) -> Link<Link<P0, P1>, Link<P2, P3>> {
Link(previous: Link(previous: p0, behind: p1), behind: Link(previous: p2, behind: p3))
}
static func buildBlock<P0, P1, P2, P3, P4>(_ p0: P0, _ p1: P1, _ p2: P2, _ p3: P3, _ p4: P4) -> Link<Link<P0, Link<P1, P2>>, Link<P3, P4>> {
Link(previous: Link(previous: p0, behind: Link(previous: p1, behind: p2)), behind: Link(previous: p3, behind: p4))
}
} 次に func bundleBuilder<T: BuilderElement>(@BundleBuilder _ statement: () -> T) -> T {
statement()
} Bundle protocolBundle protocol を定義します。 protocol Bundle {
associatedtype Body: BuilderElement
var body: Body { get }
} このままでは使いづらい( func component<T>(_ c: T) -> End<T> {
End(initialValue: c)
}
func bundle<T: Bundle>(_ b: T) -> T.Body {
b.body
} おまけ bundle builder の結果たとえば、上記の Link<End<Size>, Link<End<Texture>, Link<End<Pos>, End<ZPos>>>>(
previous: End<Size>(
initialValue: Size()
),
behind: Link<End<Texture>, Link<End<Pos>, End<ZPos>>>(
previous: End<Texture>(
initialValue: Texture()
),
behind: Link<End<Pos>, End<ZPos>>(
previous: End<Pos>(
initialValue: Pos()
),
behind: End<ZPos>(
initialValue: ZPos()
)
)
)
) |
Swift macros を使った API が実装できないか検討してください。 |
イメージですが、型アノテーション付きで全プロパティを定義し、型の記述部分をコード文字列として受け取れるかもしれません。 受け取った型に関するコード文字を使って bundle を組み立てるメソッドを作れるかも。 |
Macro かけました。 実装 struct BundleMacro: MemberMacro {
static func expansion(
of node: AttributeSyntax,
providingMembersOf declaration: some DeclGroupSyntax,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
let membersAddition = declaration.memberBlock.members
.compactMap { $0.decl.as(VariableDeclSyntax.self) }
.compactMap { i in
i.bindings.first?.pattern.as(IdentifierPatternSyntax.self)?.identifier.text
}
.reduce(into: "") { partialResult, identifier in
partialResult.append("record.addComponent(self.\(identifier))\n")
}
.dropLast()
return [
"""
public func addComponent(forEntity record: EntityRecord) {
\(raw: membersAddition)
}
"""
]
}
} Macro @attached(member, names: named(addComponent))
public macro Bundle() = #externalMacro(module: "MacroSampleMacros", type: "BundleMacro") 使い方 public protocol Component {
}
public class EntityRecord {
public func addComponent<C: Component>(_ component: C) {
}
}
@Bundle
struct MyBuldle {
let id: Int
let name: String
let position = Position(x: 0, y: 0)
}
func sample() {
let b = MyBuldle(id: 0, name: "")
b.addComponent(forEntity: EntityRecord())
} 展開されているコード @Bundle
struct MyBuldle {
let id: Int
let name: String
let position = Position(x: 0, y: 0)
// 展開コード
// ```
public func addComponent(forEntity record: EntityRecord) {
record.addComponent(self.id)
record.addComponent(self.name)
record.addComponent(self.position)
}
// ```
} |
#94 |
作れそうだったら作ってみたいです。以下のようなイメージですが、はたして実現可能なのか..?
例: グラフィック用データの定義
最新の検討案の欄
The text was updated successfully, but these errors were encountered: