Skip to content

Commit

Permalink
Add BodyAccessor Support (#38)
Browse files Browse the repository at this point in the history
* Update GraphHost

* Update GraphValue and GraphInputs

* Add BodyAccessor and BodyAccessorRule

* Add StaticBody implementation

* Complete missing part of StaticBody

* Update StaticBody

* Add BodyAccessor.makeBody logic

* Workaround non-Darwin platform build issue

Tracked with #39

* Add scripts and update swift-syntax version
  • Loading branch information
Kyle-Ye committed Feb 25, 2024
1 parent deb8e9d commit 75b0f6a
Show file tree
Hide file tree
Showing 17 changed files with 396 additions and 78 deletions.
6 changes: 3 additions & 3 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
"location" : "https://github.com/OpenSwiftUIProject/OpenGraph",
"state" : {
"branch" : "main",
"revision" : "8cc89abc1fff74b387a083eab8ffa91f1b9fdca7"
"revision" : "6133e9f737077b5c75ff33dee1c2c969cb5d91b4"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036",
"version" : "509.0.2"
"revision" : "64889f0c732f210a935a0ad7cda38f77f876262d",
"version" : "509.1.1"
}
},
{
Expand Down
30 changes: 30 additions & 0 deletions Scripts/demangle.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/zsh

# A `realpath` alternative using the default C implementation.
filepath() {
[[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

OG_ROOT="$(dirname $(dirname $(filepath $0)))"

# Get the language and input file path from the arguments
language=${1:-"swift"}
input_file=${2:-"$(dirname $(filepath $0))/demangle.txt"}

echo "Demangling $input_file using $language mode"

# Read each line of the input file
while IFS= read -r line; do
# Demangle the line using the appropriate tool based on the language
if [[ $language == "swift" ]]; then
xcrun swift-demangle "$line"
elif [[ $language == "c++" ]]; then
c++filt "$line"
else
echo "Invalid language: $language"
echo "Usage: demangle.sh <language> <input file>"
echo "language: swift or c++, [default]: swift"
echo "input file: [default] demangle.txt"
exit 1
fi
done < "$input_file"
Empty file added Scripts/demangle.txt
Empty file.
14 changes: 14 additions & 0 deletions Scripts/openswiftui_swiftinterface.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/zsh

# A `realpath` alternative using the default C implementation.
filepath() {
[[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

OPENSWIFTUI_ROOT="$(dirname $(dirname $(filepath $0)))"

cd $OPENSWIFTUI_ROOT

export OPENSWIFTUI_SWIFT_TESTING=0
export OPENGRAPH_SWIFT_TESTING=0
swift build -c release -Xswiftc -emit-module-interface -Xswiftc -enable-library-evolution
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
// Created by Kyle on 2023/11/2.
// Lastest Version: iOS 15.5
// Status: Complete
// ID: 49D2A32E637CD497C6DE29B8E060A506

internal import OpenGraphShims

/// An interface for a stored variable that updates an external property of a
/// view.
Expand All @@ -29,8 +32,209 @@ public protocol DynamicProperty {
mutating func update()
}

// MARK: Default implementation for DynamicProperty

extension DynamicProperty {
public static func _makeProperty<Value>(
in buffer: inout _DynamicPropertyBuffer,
container: _GraphValue<Value>,
fieldOffset: Int,
inputs: inout _GraphInputs
) {
makeEmbeddedProperties(
in: &buffer,
container: container,
fieldOffset: fieldOffset,
inputs: &inputs
)
buffer.append(
EmbeddedDynamicPropertyBox<Self>(),
fieldOffset: fieldOffset
)
}

public static var _propertyBehaviors: UInt32 { 0 }

public mutating func update() {}
}

// MARK: - EmbeddedDynamicPropertyBox

private struct EmbeddedDynamicPropertyBox<Value: DynamicProperty>: DynamicPropertyBox {
typealias Property = Value
func destroy() {}
func reset() {}
func update(property: inout Property, phase _: _GraphInputs.Phase) -> Bool {
property.update()
return false
}
}

extension DynamicProperty {
static func makeEmbeddedProperties<Value>(
in buffer: inout _DynamicPropertyBuffer,
container: _GraphValue<Value>,
fieldOffset: Int,
inputs: inout _GraphInputs
) {
let fields = DynamicPropertyCache.fields(of: self)
buffer.addFields(
fields,
container: container,
inputs: &inputs,
baseOffset: fieldOffset
)
}
}

// FIXME: Compile crash on non-ObjectiveC platform
// https://github.com/OpenSwiftUIProject/OpenSwiftUI/issues/39
#if canImport(Darwin)
extension BodyAccessor {
func makeBody(
container: _GraphValue<Container>,
inputs: inout _GraphInputs,
fields: DynamicPropertyCache.Fields
) -> (_GraphValue<Body>, _DynamicPropertyBuffer?) {
guard Body.self != Never.self else {
fatalError("\(Body.self) may not have Body == Never")
}
return withUnsafeMutablePointer(to: &inputs) { inputsPointer in
func project<Flags: RuleThreadFlags>(flags _: Flags.Type) -> (_GraphValue<Body>, _DynamicPropertyBuffer?) {
let buffer = _DynamicPropertyBuffer(
fields: fields,
container: container,
inputs: &inputsPointer.pointee
)
if buffer._count == 0 {
buffer.destroy()
let body = StaticBody<Self, Flags>(
accessor: self,
container: container.value
)
return (_GraphValue(body), nil)
} else {
let body = DynamicBody<Self, Flags>(
accessor: self,
container: container.value,
phase: inputsPointer.pointee.phase,
links: buffer,
resetSeed: 0
)
return (_GraphValue(body), buffer)
}
}
if fields.behaviors.contains(.asyncThread) {
return project(flags: AsyncThreadFlags.self)
} else {
return project(flags: MainThreadFlags.self)
}
}
}
}

// MARK: - RuleThreadFlags

private protocol RuleThreadFlags {
static var value: OGAttributeTypeFlags { get }
}

private struct AsyncThreadFlags: RuleThreadFlags {
static var value: OGAttributeTypeFlags { .asyncThread }
}

private struct MainThreadFlags: RuleThreadFlags {
static var value: OGAttributeTypeFlags { .mainThread }
}

// MARK: - StaticBody

private struct StaticBody<Accessor: BodyAccessor, ThreadFlags: RuleThreadFlags> {
let accessor: Accessor
@Attribute
var container: Accessor.Container

init(accessor: Accessor, container: Attribute<Accessor.Container>) {
self.accessor = accessor
self._container = container
}
}

extension StaticBody: StatefulRule {
typealias Value = Accessor.Body

func updateValue() {
accessor.updateBody(of: container, changed: true)
}
}

extension StaticBody: _AttributeBody {
static var flags: OGAttributeTypeFlags {
ThreadFlags.value
}
}

extension StaticBody: BodyAccessorRule {
static var container: Any.Type {
Accessor.Container.self
}

static func buffer<Value>(as type: Value.Type, attribute: OGAttribute) -> _DynamicPropertyBuffer? {
nil
}

static func value<Value>(as type: Value.Type, attribute: OGAttribute) -> Value? {
guard container == type else {
return nil
}
return (attribute.info.body.assumingMemoryBound(to: Self.self).pointee.container as! Value)
}

static func metaProperties<Value>(as type: Value.Type, attribute: OGAttribute) -> [(String, OGAttribute)] {
guard container == type else {
return []
}
return [("@self", attribute.info.body.assumingMemoryBound(to: Self.self).pointee._container.identifier)]
}
}

extension StaticBody: CustomStringConvertible {
var description: String { "\(Accessor.Body.self)" }
}

// MARK: - DynamicBody

// TODO
private struct DynamicBody<Accessor: BodyAccessor, ThreadFlags: RuleThreadFlags> {
let accessor: Accessor
@Attribute
var container: Accessor.Container
@Attribute
var phase: _GraphInputs.Phase
var links: _DynamicPropertyBuffer
var resetSeed: UInt32

init(
accessor: Accessor,
container: Attribute<Accessor.Container>,
phase: Attribute<_GraphInputs.Phase>,
links: _DynamicPropertyBuffer,
resetSeed: UInt32
) {
fatalError("TODO")
// self.accessor = accessor
// self._container = container
// self._phase = phase
// self.links = links
// self.resetSeed = resetSeed
}
}

extension DynamicBody: StatefulRule {
typealias Value = Accessor.Body

func updateValue() {
// TODO
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@

struct DynamicPropertyBehaviors: OptionSet {
let rawValue: UInt32
static var asyncThread: DynamicPropertyBehaviors { .init(rawValue: 1 << 0) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public struct _DynamicPropertyBuffer {
fields: DynamicPropertyCache.Fields,
container: _GraphValue<Value>,
inputs: inout _GraphInputs,
baseOffset: Int
baseOffset: Int = 0
) {
self.init()
addFields(fields, container: container, inputs: &inputs, baseOffset: baseOffset)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,50 +113,3 @@ extension DynamicPropertyCache {
var fields: [Field]
}
}

// MARK: - EmbeddedDynamicPropertyBox

private struct EmbeddedDynamicPropertyBox<Value: DynamicProperty>: DynamicPropertyBox {
typealias Property = Value
func destroy() {}
func reset() {}
func update(property: inout Property, phase _: _GraphInputs.Phase) -> Bool {
property.update()
return false
}
}

extension DynamicProperty {
public static func _makeProperty<Value>(
in buffer: inout _DynamicPropertyBuffer,
container: _GraphValue<Value>,
fieldOffset: Int,
inputs: inout _GraphInputs
) {
makeEmbeddedProperties(
in: &buffer,
container: container,
fieldOffset: fieldOffset,
inputs: &inputs
)
buffer.append(
EmbeddedDynamicPropertyBox<Self>(),
fieldOffset: fieldOffset
)
}

static func makeEmbeddedProperties<Value>(
in buffer: inout _DynamicPropertyBuffer,
container: _GraphValue<Value>,
fieldOffset: Int,
inputs: inout _GraphInputs
) -> () {
let fields = DynamicPropertyCache.fields(of: self)
buffer.addFields(
fields,
container: container,
inputs: &inputs,
baseOffset: fieldOffset
)
}
}
13 changes: 13 additions & 0 deletions Sources/OpenSwiftUI/Internal/BodyAccessor/BodyAccessor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// BodyAccessor.swift
// OpenSwiftUI
//
// Created by Kyle on 2024/2/21.
// Lastest Version: iOS 15.5
// Status: Complete

protocol BodyAccessor<Container, Body> {
associatedtype Container
associatedtype Body
func updateBody(of: Container, changed: Bool)
}
16 changes: 16 additions & 0 deletions Sources/OpenSwiftUI/Internal/BodyAccessor/BodyAccessorRule.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// BodyAccessorRule.swift
// OpenSwiftUI
//
// Created by Kyle on 2024/2/21.
// Lastest Version: iOS 15.5
// Status: Complete

internal import OpenGraphShims

protocol BodyAccessorRule {
static var container: Any.Type { get }
static func value<Value>(as: Value.Type, attribute: OGAttribute) -> Value?
static func buffer<Value>(as: Value.Type, attribute: OGAttribute) -> _DynamicPropertyBuffer?
static func metaProperties<Value>(as: Value.Type, attribute: OGAttribute) -> [(String, OGAttribute)]
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
//
// _Graph.swift
// Graph.swift
// OpenSwiftUI
//
// Created by Kyle on 2023/9/24.
// Lastest Version: iOS 15.5
// Status: Complete

public struct _Graph {
}
public struct _Graph {}
Loading

0 comments on commit 75b0f6a

Please sign in to comment.