Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
daa75c48
Commit
daa75c48
authored
Dec 16, 2022
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Plain Diff
Merge topic/neverlord/future-to-observable
parents
95aeba25
85731549
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
83 additions
and
9 deletions
+83
-9
CHANGELOG.md
CHANGELOG.md
+4
-2
libcaf_core/caf/async/future.hpp
libcaf_core/caf/async/future.hpp
+13
-0
libcaf_core/test/async/promise.cpp
libcaf_core/test/async/promise.cpp
+66
-7
No files found.
CHANGELOG.md
View file @
daa75c48
...
...
@@ -9,14 +9,16 @@ is based on [Keep a Changelog](https://keepachangelog.com).
-
The new classes
`json_value`
,
`json_array`
and
`json_object`
allow working
with JSON inputs directly. Actors can also pass around JSON values safely.
-
Fu
sed stages now properly forward errors during the initial subscription to
their observer
.
-
Fu
tures can now convert to observable values for making it easier to process
asynchronous results with data flows
.
### Fixed
-
The SPSC buffer now makes sure that subscribers get informed of a producer has
already left before the subscriber appeared and vice versa. This fixes a race
on the buffer that could cause indefinite hanging of an application.
-
Fused stages now properly forward errors during the initial subscription to
their observer.
## [0.19.0-rc.1] - 2022-10-31
...
...
libcaf_core/caf/async/future.hpp
View file @
daa75c48
...
...
@@ -9,6 +9,8 @@
#include "caf/detail/async_cell.hpp"
#include "caf/disposable.hpp"
#include "caf/error.hpp"
#include "caf/flow/observable.hpp"
#include "caf/flow/op/cell.hpp"
#include "caf/sec.hpp"
namespace
caf
::
async
{
...
...
@@ -128,6 +130,17 @@ public:
return
{
&
ctx
,
cell_
};
}
/// Binds this future to a @ref coordinator and converts it to an
/// @ref observable.
/// @pre `valid()`
flow
::
observable
<
T
>
observe_on
(
flow
::
coordinator
*
ctx
)
const
{
using
flow_cell_t
=
flow
::
op
::
cell
<
T
>
;
auto
ptr
=
make_counted
<
flow_cell_t
>
(
ctx
);
bind_to
(
ctx
).
then
([
ptr
](
const
T
&
val
)
{
ptr
->
set_value
(
val
);
},
[
ptr
](
const
error
&
what
)
{
ptr
->
set_error
(
what
);
});
return
flow
::
observable
<
T
>
{
ptr
};
}
/// Queries whether the result of the asynchronous computation is still
/// pending, i.e., neither `set_value` nor `set_error` has been called on the
/// @ref promise.
...
...
libcaf_core/test/async/promise.cpp
View file @
daa75c48
...
...
@@ -14,13 +14,28 @@
using
namespace
caf
;
using
namespace
std
::
literals
;
namespace
{
template
<
class
T
>
auto
make_shared_val_ptr
()
{
return
std
::
make_shared
<
std
::
variant
<
none_t
,
T
,
error
>>
();
}
template
<
class
T
>
auto
make_observer
(
std
::
shared_ptr
<
std
::
variant
<
none_t
,
T
,
error
>>
ptr
)
{
return
flow
::
make_observer
([
ptr
](
const
T
&
val
)
{
*
ptr
=
val
;
},
[
ptr
](
const
error
&
what
)
{
*
ptr
=
what
;
});
}
}
// namespace
BEGIN_FIXTURE_SCOPE
(
test_coordinator_fixture
<>
)
SCENARIO
(
"actors can observe futures"
)
{
GIVEN
(
"a promise and future pair"
)
{
WHEN
(
"passing a non-ready future to an actor"
)
{
THEN
(
"
the actor
can observe the value via .then() later"
)
{
auto
val
=
std
::
make_shared
<
std
::
variant
<
none_t
,
std
::
string
,
error
>
>
();
THEN
(
"
it
can observe the value via .then() later"
)
{
auto
val
=
make_shared_val_ptr
<
std
::
string
>
();
auto
uut
=
async
::
promise
<
std
::
string
>
{};
auto
fut
=
uut
.
get_future
();
auto
testee
=
sys
.
spawn
([
val
,
fut
](
event_based_actor
*
self
)
{
...
...
@@ -34,10 +49,24 @@ SCENARIO("actors can observe futures") {
if
(
CHECK
(
std
::
holds_alternative
<
std
::
string
>
(
*
val
)))
CHECK_EQ
(
std
::
get
<
std
::
string
>
(
*
val
),
"hello world"
);
}
AND_THEN
(
"it can observe the value via .observe_on() later"
)
{
auto
val
=
make_shared_val_ptr
<
std
::
string
>
();
auto
uut
=
async
::
promise
<
std
::
string
>
{};
auto
fut
=
uut
.
get_future
();
auto
testee
=
sys
.
spawn
([
val
,
fut
](
event_based_actor
*
self
)
{
fut
.
observe_on
(
self
).
subscribe
(
make_observer
(
val
));
});
run
();
CHECK
(
std
::
holds_alternative
<
none_t
>
(
*
val
));
uut
.
set_value
(
"hello world"
s
);
expect
((
action
),
to
(
testee
));
if
(
CHECK
(
std
::
holds_alternative
<
std
::
string
>
(
*
val
)))
CHECK_EQ
(
std
::
get
<
std
::
string
>
(
*
val
),
"hello world"
);
}
}
WHEN
(
"passing a ready future to an actor"
)
{
THEN
(
"
the actor
can observe the value via .then() immediately"
)
{
auto
val
=
std
::
make_shared
<
std
::
variant
<
none_t
,
std
::
string
,
error
>
>
();
THEN
(
"
it
can observe the value via .then() immediately"
)
{
auto
val
=
make_shared_val_ptr
<
std
::
string
>
();
auto
uut
=
async
::
promise
<
std
::
string
>
{};
auto
fut
=
uut
.
get_future
();
uut
.
set_value
(
"hello world"
s
);
...
...
@@ -49,10 +78,22 @@ SCENARIO("actors can observe futures") {
if
(
CHECK
(
std
::
holds_alternative
<
std
::
string
>
(
*
val
)))
CHECK_EQ
(
std
::
get
<
std
::
string
>
(
*
val
),
"hello world"
);
}
AND_THEN
(
"it can observe the value via .observe_on() immediately"
)
{
auto
val
=
make_shared_val_ptr
<
std
::
string
>
();
auto
uut
=
async
::
promise
<
std
::
string
>
{};
auto
fut
=
uut
.
get_future
();
uut
.
set_value
(
"hello world"
s
);
auto
testee
=
sys
.
spawn
([
val
,
fut
](
event_based_actor
*
self
)
{
fut
.
observe_on
(
self
).
subscribe
(
make_observer
(
val
));
});
run
();
if
(
CHECK
(
std
::
holds_alternative
<
std
::
string
>
(
*
val
)))
CHECK_EQ
(
std
::
get
<
std
::
string
>
(
*
val
),
"hello world"
);
}
}
WHEN
(
"passing a non-ready future to an actor and disposing the action"
)
{
THEN
(
"
the actor never observes the value
"
)
{
auto
val
=
std
::
make_shared
<
std
::
variant
<
none_t
,
std
::
string
,
error
>
>
();
THEN
(
"
it never observes the value with .then()
"
)
{
auto
val
=
make_shared_val_ptr
<
std
::
string
>
();
auto
uut
=
async
::
promise
<
std
::
string
>
{};
auto
fut
=
uut
.
get_future
();
auto
hdl
=
disposable
{};
...
...
@@ -75,7 +116,7 @@ SCENARIO("actors can observe futures") {
SCENARIO
(
"never setting a value or an error breaks the promises"
)
{
GIVEN
(
"multiple promises that point to the same cell"
)
{
WHEN
(
"the last promise goes out of scope"
)
{
THEN
(
"the future reports a broken promise"
)
{
THEN
(
"the future reports a broken promise
when using .then()
"
)
{
using
promise_t
=
async
::
promise
<
int32_t
>
;
using
future_t
=
async
::
future
<
int32_t
>
;
future_t
fut
;
...
...
@@ -119,6 +160,24 @@ SCENARIO("never setting a value or an error breaks the promises") {
ctx
->
run
();
CHECK_EQ
(
observed_events
,
1u
);
}
AND_THEN
(
"the future reports a broken promise when using .observe_on()"
)
{
using
promise_t
=
async
::
promise
<
int32_t
>
;
using
future_t
=
async
::
future
<
int32_t
>
;
future_t
fut
;
{
auto
uut
=
promise_t
{};
fut
=
uut
.
get_future
();
CHECK
(
fut
.
pending
());
}
CHECK
(
!
fut
.
pending
());
auto
val
=
make_shared_val_ptr
<
int32_t
>
();
sys
.
spawn
([
val
,
fut
](
event_based_actor
*
self
)
{
fut
.
observe_on
(
self
).
subscribe
(
make_observer
(
val
));
});
run
();
if
(
CHECK
(
std
::
holds_alternative
<
error
>
(
*
val
)))
CHECK_EQ
(
std
::
get
<
error
>
(
*
val
),
sec
::
broken_promise
);
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment