1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2
3 #pragma once
4
5 #if !defined(RXCPP_SOURCES_RX_SCOPE_HPP)
6 #define RXCPP_SOURCES_RX_SCOPE_HPP
7
8 #include "../rx-includes.hpp"
9
10 /*! \file rx-scope.hpp
11
12 \brief Returns an observable that makes an observable by the specified observable factory using the resource provided by the specified resource factory for each new observer that subscribes.
13
14 \tparam ResourceFactory the type of the resource factory
15 \tparam ObservableFactory the type of the observable factory
16
17 \param rf the resource factory function that resturn the rxcpp::resource that is used as a resource by the observable factory
18 \param of the observable factory function to invoke for each observer that subscribes to the resulting observable
19
20 \return observable that makes an observable by the specified observable factory using the resource provided by the specified resource factory for each new observer that subscribes.
21
22 \sample
23 \snippet scope.cpp scope sample
24 \snippet output.txt scope sample
25 */
26
27 namespace rxcpp {
28
29 namespace sources {
30
31 namespace detail {
32
33 template<class ResourceFactory, class ObservableFactory>
34 struct scope_traits
35 {
36 typedef rxu::decay_t<ResourceFactory> resource_factory_type;
37 typedef rxu::decay_t<ObservableFactory> observable_factory_type;
38 typedef decltype((*(resource_factory_type*)nullptr)()) resource_type;
39 typedef decltype((*(observable_factory_type*)nullptr)(resource_type())) collection_type;
40 typedef typename collection_type::value_type value_type;
41
42 static_assert(is_subscription<resource_type>::value, "ResourceFactory must return a subscription");
43 };
44
45 template<class ResourceFactory, class ObservableFactory>
46 struct scope : public source_base<rxu::value_type_t<scope_traits<ResourceFactory, ObservableFactory>>>
47 {
48 typedef scope_traits<ResourceFactory, ObservableFactory> traits;
49 typedef typename traits::resource_factory_type resource_factory_type;
50 typedef typename traits::observable_factory_type observable_factory_type;
51 typedef typename traits::resource_type resource_type;
52 typedef typename traits::value_type value_type;
53
54 struct values
55 {
valuesrxcpp::sources::detail::scope::values56 values(resource_factory_type rf, observable_factory_type of)
57 : resource_factory(std::move(rf))
58 , observable_factory(std::move(of))
59 {
60 }
61 resource_factory_type resource_factory;
62 observable_factory_type observable_factory;
63 };
64 values initial;
65
66
scoperxcpp::sources::detail::scope67 scope(resource_factory_type rf, observable_factory_type of)
68 : initial(std::move(rf), std::move(of))
69 {
70 }
71
72 template<class Subscriber>
on_subscriberxcpp::sources::detail::scope73 void on_subscribe(Subscriber o) const {
74
75 struct state_type
76 : public std::enable_shared_from_this<state_type>
77 , public values
78 {
79 state_type(values i, Subscriber o)
80 : values(i)
81 , out(std::move(o))
82 {
83 }
84 Subscriber out;
85 rxu::detail::maybe<resource_type> resource;
86 };
87
88 auto state = std::make_shared<state_type>(state_type(initial, std::move(o)));
89
90 state->resource = on_exception(
91 [&](){return state->resource_factory(); },
92 state->out);
93 if (state->resource.empty()) {
94 return;
95 }
96 state->out.add(state->resource->get_subscription());
97
98 auto selectedCollection = on_exception(
99 [state](){return state->observable_factory(state->resource.get()); },
100 state->out);
101 if (selectedCollection.empty()) {
102 return;
103 }
104
105 selectedCollection->subscribe(state->out);
106 }
107 };
108
109 }
110
111 /*! @copydoc rx-scope.hpp
112 */
113 template<class ResourceFactory, class ObservableFactory>
scope(ResourceFactory rf,ObservableFactory of)114 auto scope(ResourceFactory rf, ObservableFactory of)
115 -> observable<rxu::value_type_t<detail::scope_traits<ResourceFactory, ObservableFactory>>, detail::scope<ResourceFactory, ObservableFactory>> {
116 return observable<rxu::value_type_t<detail::scope_traits<ResourceFactory, ObservableFactory>>, detail::scope<ResourceFactory, ObservableFactory>>(
117 detail::scope<ResourceFactory, ObservableFactory>(std::move(rf), std::move(of)));
118 }
119
120 }
121
122 }
123
124 #endif
125