@@ -63,6 +63,7 @@ static void futureTaskInvokeFunction(AsyncTask *task, ExecutorRef executor,
63
63
64
64
template <class T >
65
65
static void withFutureTask (const Metadata *resultType,
66
+ const T& initialValue,
66
67
undeduced<InvokeFunctionRef<T>> invokeFn,
67
68
BodyFunctionRef body) {
68
69
JobFlags flags = JobKind::Task;
@@ -77,7 +78,7 @@ static void withFutureTask(const Metadata *resultType,
77
78
78
79
auto futureContext =
79
80
static_cast <FutureContext<T>*>(taskAndContext.InitialContext );
80
- futureContext->getStorage () = 42 ; // Magic number.
81
+ futureContext->getStorage () = initialValue ; // Magic number.
81
82
futureContext->storedInvokeFn = invokeFn;
82
83
83
84
// Forward our owning reference to the task into its execution,
@@ -92,12 +93,46 @@ static ExecutorRef createFakeExecutor(uintptr_t value) {
92
93
93
94
extern const FullMetadata<OpaqueMetadata> METADATA_SYM (Si);
94
95
96
+ struct TestObject : HeapObject {
97
+ constexpr TestObject (HeapMetadata const *newMetadata)
98
+ : HeapObject(newMetadata, InlineRefCounts::Immortal)
99
+ , Addr(NULL ), Value(0 ) {}
100
+
101
+ size_t *Addr;
102
+ size_t Value;
103
+ };
104
+
105
+ static SWIFT_CC (swift) void destroyTestObject(SWIFT_CONTEXT HeapObject *_object) {
106
+ auto object = static_cast <TestObject*>(_object);
107
+ assert (object->Addr && " object already deallocated" );
108
+ *object->Addr = object->Value ;
109
+ object->Addr = nullptr ;
110
+ swift_deallocObject (object, sizeof (TestObject), alignof (TestObject) - 1 );
111
+ }
112
+
113
+ static const FullMetadata<ClassMetadata> TestClassObjectMetadata = {
114
+ { { &destroyTestObject }, { &VALUE_WITNESS_SYM (Bo) } },
115
+ { { nullptr }, ClassFlags::UsesSwiftRefcounting, 0 , 0 , 0 , 0 , 0 , 0 }
116
+ };
117
+
118
+ // / Create an object that, when deallocated, stores the given value to
119
+ // / the given pointer.
120
+ static TestObject *allocTestObject (size_t *addr, size_t value) {
121
+ auto result =
122
+ static_cast <TestObject *>(swift_allocObject (&TestClassObjectMetadata,
123
+ sizeof (TestObject),
124
+ alignof (TestObject) - 1 ));
125
+ result->Addr = addr;
126
+ result->Value = value;
127
+ return result;
128
+ }
129
+
95
130
TEST (TaskFutureTest, intFuture) {
96
131
auto createdExecutor = createFakeExecutor (1234 );
97
132
bool hasRun = false ;
98
133
99
134
withFutureTask<intptr_t >(
100
- reinterpret_cast <const Metadata *>(&METADATA_SYM (Si)),
135
+ reinterpret_cast <const Metadata *>(&METADATA_SYM (Si)), 42 ,
101
136
[&](AsyncTask *task, ExecutorRef executor,
102
137
FutureContext<intptr_t > *context) {
103
138
// The storage should be what we initialized it to earlier.
@@ -125,3 +160,47 @@ TEST(TaskFutureTest, intFuture) {
125
160
});
126
161
}
127
162
163
+ TEST (TaskFutureTest, objectFuture) {
164
+ auto createdExecutor = createFakeExecutor (1234 );
165
+ bool hasRun = false ;
166
+
167
+ size_t objectValueOnComplete = 7 ;
168
+ TestObject *object = nullptr ;
169
+ withFutureTask<TestObject *>(
170
+ &TestClassObjectMetadata, nullptr ,
171
+ [&](AsyncTask *task, ExecutorRef executor,
172
+ FutureContext<TestObject *> *context) {
173
+ object = allocTestObject (&objectValueOnComplete, 25 );
174
+
175
+ // The error storage should have been cleared out for us.
176
+ EXPECT_EQ (nullptr , context->errorStorage );
177
+
178
+ // Store the object in the future.
179
+ context->getStorage () = object;
180
+
181
+ hasRun = true ;
182
+ }, [&](AsyncTask *task) {
183
+ // Retain the task, so it won't be destroyed when it is executed.
184
+ swift_retain (task);
185
+
186
+ // Run the task, which should fill in the future.
187
+ EXPECT_FALSE (hasRun);
188
+ task->run (createdExecutor);
189
+ EXPECT_TRUE (hasRun);
190
+
191
+ // "Wait" for the future, which must have completed by now.
192
+ auto waitResult = swift_task_future_wait (task, nullptr );
193
+ EXPECT_EQ (TaskFutureWaitResult::Success, waitResult.kind );
194
+
195
+ // Make sure we got the result value we expect.
196
+ EXPECT_EQ (object, *reinterpret_cast <TestObject **>(waitResult.storage ));
197
+
198
+ // Make sure the object hasn't been destroyed.
199
+ EXPECT_EQ (7 , objectValueOnComplete);
200
+
201
+ // Okay, release the task. This should destroy the object.
202
+ swift_release (task);
203
+ assert (objectValueOnComplete == 25 );
204
+ });
205
+
206
+ }
0 commit comments