Skip to content

Commit

Permalink
Promises: WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
kosyloa committed Jan 29, 2024
1 parent 0880e92 commit 48a3dc7
Show file tree
Hide file tree
Showing 4 changed files with 343 additions and 0 deletions.
28 changes: 28 additions & 0 deletions DXFeedFramework.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@
64ECD6822A9DDC2800B36935 /* DXInstrumentProfileReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64ECD6812A9DDC2800B36935 /* DXInstrumentProfileReader.swift */; };
64ECD6852A9DDF6200B36935 /* DXInstrumentProfileCollector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64ECD6842A9DDF6200B36935 /* DXInstrumentProfileCollector.swift */; };
64ECD6872A9DDFBE00B36935 /* DXInstrumentProfileConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64ECD6862A9DDFBE00B36935 /* DXInstrumentProfileConnection.swift */; };
64F73B9F2B6788B00088EC37 /* Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F73B9E2B6788B00088EC37 /* Promise.swift */; };
64F73BA42B67B28B0088EC37 /* NativePromise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F73BA32B67B28B0088EC37 /* NativePromise.swift */; };
64F73BA62B67CD5B0088EC37 /* GraalException+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F73BA52B67CD5B0088EC37 /* GraalException+Ext.swift */; };
64FCAF902A572D4600971F4E /* libDxFeedGraalNativeSdk.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 64125E352A1F689A00FB32BA /* libDxFeedGraalNativeSdk.dylib */; platformFilters = (macos, ); settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
803BAC1629BFA50700FFAB1C /* DXFeedFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 803BAC0D29BFA50700FFAB1C /* DXFeedFramework.framework */; };
803BAC1C29BFA50700FFAB1C /* DxFeedSwiftFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 803BAC1029BFA50700FFAB1C /* DxFeedSwiftFramework.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -854,6 +857,9 @@
64ECD6812A9DDC2800B36935 /* DXInstrumentProfileReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DXInstrumentProfileReader.swift; sourceTree = "<group>"; };
64ECD6842A9DDF6200B36935 /* DXInstrumentProfileCollector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DXInstrumentProfileCollector.swift; sourceTree = "<group>"; };
64ECD6862A9DDFBE00B36935 /* DXInstrumentProfileConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DXInstrumentProfileConnection.swift; sourceTree = "<group>"; };
64F73B9E2B6788B00088EC37 /* Promise.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Promise.swift; sourceTree = "<group>"; };
64F73BA32B67B28B0088EC37 /* NativePromise.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativePromise.swift; sourceTree = "<group>"; };
64F73BA52B67CD5B0088EC37 /* GraalException+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GraalException+Ext.swift"; sourceTree = "<group>"; };
64F9C6C12B4BFD8F003ED014 /* DXFeedconnect.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DXFeedconnect.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
803BAC0D29BFA50700FFAB1C /* DXFeedFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DXFeedFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; };
803BAC1029BFA50700FFAB1C /* DxFeedSwiftFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DxFeedSwiftFramework.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1490,6 +1496,22 @@
path = Live;
sourceTree = "<group>";
};
64F73B9D2B67863B0088EC37 /* Promise */ = {
isa = PBXGroup;
children = (
64F73B9E2B6788B00088EC37 /* Promise.swift */,
);
path = Promise;
sourceTree = "<group>";
};
64F73BA22B67B2750088EC37 /* Promise */ = {
isa = PBXGroup;
children = (
64F73BA32B67B28B0088EC37 /* NativePromise.swift */,
);
path = Promise;
sourceTree = "<group>";
};
803BAC0329BFA50700FFAB1C = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1529,6 +1551,7 @@
8088D77A29C5D8AD00F240CB /* Native */,
64656F552A1B6A07006A0B19 /* Utils */,
64ECD6802A9DD80000B36935 /* Ipf */,
64F73B9D2B67863B0088EC37 /* Promise */,
64C771FD2A9504D7009868C2 /* Extra */,
6498E6B02AB1D40C0093A065 /* Schedule */,
8088D77029C3A25D00F240CB /* SystemProperty.swift */,
Expand Down Expand Up @@ -1590,6 +1613,7 @@
64104FCA2A2629C400D1FC41 /* Subscription */,
64437A902A9DF1C4005929B2 /* Ipf */,
6498E6B32AB1D43A0093A065 /* Schedule */,
64F73BA22B67B2750088EC37 /* Promise */,
64ACBCE42A28AEE200032C53 /* SymbolMappers */,
64A42F432B0B9320001C3ACC /* Utils */,
);
Expand All @@ -1604,6 +1628,7 @@
8088D77C29C8DAF800F240CB /* GraalErrorCode.swift */,
64656F612A1B9FF7006A0B19 /* EnumException.swift */,
640C3FCB2A616B6200555161 /* ArgumentException.swift */,
64F73BA52B67CD5B0088EC37 /* GraalException+Ext.swift */,
);
path = ErrorHandling;
sourceTree = "<group>";
Expand Down Expand Up @@ -2291,6 +2316,7 @@
files = (
64BDDB322AD7E5A600694210 /* SpreadOrderMapper.swift in Sources */,
64ACBCE32A289A0700032C53 /* TimeSeriesSubscriptionSymbol.swift in Sources */,
64F73B9F2B6788B00088EC37 /* Promise.swift in Sources */,
645A34952A937C7200709F29 /* BinaryInteger+Ext.swift in Sources */,
641C64B22B346A2E0023CFAD /* DXObservableSubscription.swift in Sources */,
64A42F502B0BA668001C3ACC /* DXTimeFormat.swift in Sources */,
Expand Down Expand Up @@ -2367,6 +2393,7 @@
6498E6BD2AB1E0510093A065 /* ScheduleSession.swift in Sources */,
64BDDB262AD6F6B500694210 /* IcebergType.swift in Sources */,
8088D76529C0FBCE00F240CB /* ThreadManager.swift in Sources */,
64F73BA62B67CD5B0088EC37 /* GraalException+Ext.swift in Sources */,
64DA26BE2AA20EDB005B1757 /* DXInstrumentProfileConnectionListener.swift in Sources */,
64656F732A1D0A84006A0B19 /* EndpointListener.swift in Sources */,
64BDDB282AD7D8D300694210 /* Order+Ext.swift in Sources */,
Expand Down Expand Up @@ -2468,6 +2495,7 @@
64BDDB1E2AD6CC6A00694210 /* Order.swift in Sources */,
64437A8F2A9DEE6F005929B2 /* InstrumentProfile.swift in Sources */,
64C771FA2A94D692009868C2 /* ShortSaleRestriction.swift in Sources */,
64F73BA42B67B28B0088EC37 /* NativePromise.swift in Sources */,
64656F5E2A1B97F2006A0B19 /* NativeFeed.swift in Sources */,
6486B97D2AD057F200D8D5FA /* OrderSource.swift in Sources */,
64656F6F2A1CFC12006A0B19 /* WeakBox.swift in Sources */,
Expand Down
37 changes: 37 additions & 0 deletions DXFeedFramework/Native/ErrorHandling/GraalException+Ext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
//
// Copyright (C) 2024 Devexperts LLC. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

import Foundation
@_implementationOnly import graal_api

internal extension GraalException {
static func createNew(native: UnsafeMutablePointer<dxfg_exception_t>) -> GraalException {
let pointee = native.pointee
let message = String(pointee: pointee.message, default: "Graall Exception")
let className = String(pointee: pointee.class_name, default: "")
let stackTrace = String(pointee: pointee.print_stack_trace, default: "")
let gException = GraalException.fail(message: message,
className: className,
stack: stackTrace)
return gException
}

func toNative() -> UnsafeMutablePointer<dxfg_exception_t>? {
switch self {
case .fail(message: let message, className: let className, stack: let stack):
let exception = UnsafeMutablePointer<dxfg_exception_t>.allocate(capacity: 1)
var pointee = exception.pointee
pointee.class_name = className.toCStringRef()
pointee.message = message.toCStringRef()
pointee.print_stack_trace = stack.toCStringRef()
exception.pointee = pointee
return exception
default:
return nil
}
}
}
185 changes: 185 additions & 0 deletions DXFeedFramework/Native/Promise/NativePromise.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
//
//
// Copyright (C) 2024 Devexperts LLC. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

import Foundation
@_implementationOnly import graal_api

class NativePromise {
public typealias PromiseHandler = (_: NativePromise) -> Void

let promise: UnsafeMutablePointer<dxfg_promise_t>?
private static let mapper = EventMapper()

private class WeakPromises: WeakBox<PromiseHandler> { }
private static let listeners = ConcurrentArray<WeakPromises>()

static let listenerCallback: dxfg_promise_handler_function = { _, promise, context in
if let context = context {
let listener: AnyObject = bridge(ptr: context)
if let weakListener = listener as? WeakPromises {
guard let listener = weakListener.value else {
return
}
let native = NativePromise(promise: promise)
listener(native)
NativePromise.listeners.removeAll(where: {
return $0 === weakListener
})
}
}
}

deinit {
if let promise = promise {
let thread = currentThread()
_ = try? ErrorCheck.nativeCall(
thread,
dxfg_JavaObjectHandler_release(thread,
&(promise.pointee.handler)))
}
}

init(promise: UnsafeMutablePointer<dxfg_promise_t>?) {
self.promise = promise
}

func getResult() -> MarketEvent? {
return nil
}

func hasResult() -> Bool {
let thread = currentThread()
if let result = try? ErrorCheck.nativeCall(thread, dxfg_Promise_hasResult(thread, promise)) {
return result == 1
} else {
return false
}
}

func hasException() -> Bool {
let thread = currentThread()
if let result = try? ErrorCheck.nativeCall(thread, dxfg_Promise_hasException(thread, promise)) {
return result == 1
} else {
return false
}
}

func isCancelled() -> Bool {
let thread = currentThread()
if let result = try? ErrorCheck.nativeCall(thread, dxfg_Promise_isCancelled(thread, promise)) {
return result == 1
} else {
return false
}
}

func getException() -> GraalException? {
let thread = currentThread()
if let nativeException = try? ErrorCheck.nativeCall(thread, dxfg_Promise_getException(thread, promise)) {
defer {
_ = try? ErrorCheck.nativeCall(thread, dxfg_Exception_release(thread, nativeException))
}
let exception = GraalException.createNew(native: nativeException)
return exception
}
return nil
}

func await() throws -> MarketEvent? {
let thread = currentThread()
try ErrorCheck.nativeCall(thread, dxfg_Promise_await(thread, promise))
return nil
}

func await(millis timeOut: Int32) throws -> MarketEvent? {
let thread = currentThread()
try ErrorCheck.nativeCall(thread, dxfg_Promise_await2(thread, promise, timeOut))
return nil
}

func awaitWithoutException(millis timeOut: Int32) {
let thread = currentThread()
_ = try? ErrorCheck.nativeCall(thread, dxfg_Promise_awaitWithoutException(thread, promise, timeOut))
}

func cancel() {
let thread = currentThread()
_ = try? ErrorCheck.nativeCall(thread, dxfg_Promise_cancel(thread, promise))
}

func complete(result: MarketEvent) throws {
let thread = currentThread()
let nativeEvent = try NativePromise.mapper.toNative(event: result)
try ErrorCheck.nativeCall(thread, dxfg_Promise_EventType_complete(thread, promise, nativeEvent))
}

func completeExceptionally(_ exception: GraalException) throws {
if let nativeException = exception.toNative() {
let thread = currentThread()
try ErrorCheck.nativeCall(thread, dxfg_Promise_completeExceptionally(thread, promise, nativeException))
} else {
throw ArgumentException.exception("Coudln't convert to native exception")
}
}

func whenDone(handler: @escaping NativePromise.PromiseHandler) {
let thread = currentThread()
let weakListener = WeakPromises(value: handler)
NativePromise.listeners.append(newElement: weakListener)
let voidPtr = bridge(obj: weakListener)
_ = try? ErrorCheck.nativeCall(thread,
dxfg_Promise_whenDone(thread,
promise,
NativePromise.listenerCallback,
voidPtr))
}

static func completed(result: MarketEvent) -> NativePromise? {
let thread = currentThread()
let promise = UnsafeMutablePointer<dxfg_promise_t>.allocate(capacity: 1)
if let nativeEvent = try? NativePromise.mapper.toNative(event: result) {
let handler = nativeEvent.withMemoryRebound(to: dxfg_java_object_handler.self, capacity: 1) { pointer in
return pointer
}
let result = try? ErrorCheck.nativeCall(thread, dxfg_Promise_completed(thread, promise, handler))
return NativePromise(promise: result)
}
return nil
}

static func failed(exception: GraalException) -> NativePromise? {
let thread = currentThread()
let promise = UnsafeMutablePointer<dxfg_promise_t>.allocate(capacity: 1)
if let nativeEvent = exception.toNative() {
let result = try? ErrorCheck.nativeCall(thread, dxfg_Promise_failed(thread, promise, nativeEvent))
return NativePromise(promise: result)
}
return nil
}

static func allOf(promises: [NativePromise]) throws -> NativePromise? {
let promiseList = UnsafeMutablePointer<dxfg_promise_list>.allocate(capacity: 1)
let nativeList = UnsafeMutablePointer<dxfg_java_object_handler_list>.allocate(capacity: 1)
let classes = UnsafeMutablePointer<UnsafeMutablePointer<dxfg_java_object_handler>?>
.allocate(capacity: promises.count)
var iterator = classes
for code in promises {
code.promise?.withMemoryRebound(to: dxfg_java_object_handler.self, capacity: 1, { pointer in
iterator.initialize(to: pointer)
iterator = iterator.successor()
})
}
nativeList.pointee.size = Int32(promises.count)
nativeList.pointee.elements = classes
promiseList.pointee.list = nativeList.pointee

let thread = currentThread()
let result = try ErrorCheck.nativeCall(thread, dxfg_Promises_allOf(thread, promiseList))
return NativePromise(promise: result)
}
}
Loading

0 comments on commit 48a3dc7

Please sign in to comment.