Skip to content

Commit

Permalink
Add ObservedObject implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Kyle-Ye committed Nov 5, 2023
1 parent e3ca8ef commit 3e058c1
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// ObservableObjectLocation.swift
// OpenSwiftUI
//
// Created by Kyle on 2023/11/2.
// Lastest Version: iOS 15.5
// Status: Blocked by PropertyList.Element

#if OPENSWIFTUI_USE_COMBINE
import Combine
#else
import OpenCombine
#endif
internal import OpenSwiftUIShims

struct ObservableObjectLocation<Root, Value>: Location where Root: ObservableObject {
let base: Root
let keyPath: ReferenceWritableKeyPath<Root, Value>

var wasRead: Bool {
get { true }
set {}
}
func get() -> Value { base[keyPath: keyPath] }
// FIXME
func set(_ value: Value, transaction: Transaction) {
let element = _threadTransactionData().map { Unmanaged<PropertyList.Element>.fromOpaque($0).takeRetainedValue() }
let newElement: PropertyList.Element?
if let element = transaction.plist.elements {
newElement = element.byPrepending(element)
} else {
newElement = element
}

let data = _threadTransactionData()
defer { _setThreadTransactionData(data) }
_setThreadTransactionData(newElement.map { Unmanaged.passUnretained($0).toOpaque() })
base[keyPath: keyPath] = value
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,12 @@ class LocationBox<L: Location>: AnyLocation<L.Value> {
init(location: L) {
self.location = location
}

override func get() -> L.Value {
location.get()
}

override func set(_ value: L.Value, transaction: Transaction) {
location.set(value, transaction: transaction)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ extension PropertyList {
/*@objc*/
@usableFromInline
deinit {}

func byPrepending(_ element: Element?) -> Element {
self
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//
// ObservedObject.swift
// OpenSwiftUI
//
// Created by Kyle on 2023/11/5.
// Lastest Version: iOS 15.5
// Status: Blocked by DynamicProperty

#if OPENSWIFTUI_USE_COMBINE
import Combine
#else
import OpenCombine
#endif
internal import OpenSwiftUIShims

@propertyWrapper
@frozen
public struct ObservedObject<ObjectType> where ObjectType: ObservableObject {
@dynamicMemberLookup
@frozen
public struct Wrapper {
let root: ObjectType
public subscript<Subject>(dynamicMember keyPath: ReferenceWritableKeyPath<ObjectType, Subject>) -> Binding<Subject> {
Binding(root, keyPath: keyPath)
}
}

@usableFromInline
var _seed = 0

public var wrappedValue: ObjectType

@_alwaysEmitIntoClient
public init(initialValue: ObjectType) {
self.init(wrappedValue: initialValue)
}

public init(wrappedValue: ObjectType) {
self.wrappedValue = wrappedValue
}

public var projectedValue: ObservedObject<ObjectType>.Wrapper {
.init(root: wrappedValue)
}
}

extension ObservedObject: DynamicProperty {
public static func _makeProperty(in _: inout _DynamicPropertyBuffer, container _: _GraphValue<some Any>, fieldOffset _: Int, inputs _: inout _GraphInputs) {
// TODO
}

public static var _propertyBehaviors: UInt32 { 2 }
}

extension Binding {
init<ObjectType: ObservableObject>(_ root: ObjectType, keyPath: ReferenceWritableKeyPath<ObjectType, Value>) {
let location = ObservableObjectLocation(base: root, keyPath: keyPath)
let box = LocationBox(location: location)
self.init(value: location.get(), location: box)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ func conformsToProtocol(_ type: Any.Type, _ protocolDescriptor: UnsafeRawPointer
swiftConformsToProtocol(type, protocolDescriptor) != nil
}

// FIXME: This kind usage of @_silgen_name is discouraged. But I'm not finding a way to declare or pass Any.Type to C
@_silgen_name("swift_conformsToProtocol")
@inline(__always)
private func swiftConformsToProtocol(_ type: Any.Type,
Expand Down
22 changes: 18 additions & 4 deletions Sources/OpenSwiftUI/Views/Animations/TODO/Transaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// Status: Empty
// ID: 39EC6D46662E6D7A6963F5C611934B0A

internal import OpenSwiftUIShims

@frozen
public struct Transaction {
@usableFromInline
Expand Down Expand Up @@ -34,19 +36,19 @@ extension Transaction {
// }
}

//extension Transaction {
// extension Transaction {
// public var isContinuous: Bool {
// get
// set
// }
//}
// }
//
//extension Transaction {
// extension Transaction {
// public var _scrollViewAnimates: _ScrollViewAnimationMode {
// get
// set
// }
//}
// }

protocol TransactionKey {
associatedtype Value
Expand All @@ -56,3 +58,15 @@ protocol TransactionKey {
private struct AnimationKey: TransactionKey {
static let defaultValue: Animation? = nil
}

public func withTransaction<Result>(
_ transaction: Transaction,
_ body: () throws -> Result
) rethrows -> Result {
try withExtendedLifetime(transaction) {
let data = _threadTransactionData()
defer { _setThreadTransactionData(data) }
_setThreadTransactionData(transaction.plist.elements.map { Unmanaged.passUnretained($0).toOpaque() })
return try body()
}
}
20 changes: 20 additions & 0 deletions Sources/OpenSwiftUIShims/TLS.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// TLS.c
//
//
// Created by Kyle on 2023/11/5.
//

#include "TLS.h"

static _Thread_local int64_t _perThreadUpdateCount = 0;
static _Thread_local void * _perThreadTransactionData = NULL;
static _Thread_local void * _perThreadGeometryProxyData = NULL;

void _setThreadTransactionData(void * data) {
_perThreadTransactionData = data;
}

void * _threadTransactionData(void) {
return _perThreadTransactionData;
}
20 changes: 20 additions & 0 deletions Sources/OpenSwiftUIShims/include/TLS.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// TLS.h
//
//
// Created by Kyle on 2023/11/5.
//

#ifndef TLS_h
#define TLS_h

#include <OpenFoundation/OpenFoundation.h>
#include <stdio.h>

OF_EXPORT
void _setThreadTransactionData(void * _Nullable data);

OF_EXPORT
void * _Nullable _threadTransactionData(void);

#endif /* TLS_h */

0 comments on commit 3e058c1

Please sign in to comment.