1
+ use std:: cell:: RefCell ;
2
+ use std:: marker:: PhantomData ;
3
+ use std:: rc:: Rc ;
4
+
5
+ use capnp:: capability:: { Promise , FromClientHook } ;
6
+ use capnp:: private:: capability:: { ClientHook , RequestHook } ;
7
+ use futures:: TryFutureExt ;
8
+
9
+ pub trait SetTarget < C > {
10
+ fn add_ref ( & self ) -> Box < dyn SetTarget < C > > ;
11
+ fn set_target ( & self , target : C ) ;
12
+ }
13
+
14
+ impl < C > Clone for Box < dyn SetTarget < C > > {
15
+ fn clone ( & self ) -> Self {
16
+ self . add_ref ( )
17
+ }
18
+ }
19
+
20
+ struct ClientInner < F , C > {
21
+ connect : F ,
22
+ current : Option < Box < dyn ClientHook > > ,
23
+ generation : usize ,
24
+ marker : PhantomData < C > ,
25
+ }
26
+
27
+ impl < F , C > ClientInner < F , C >
28
+ where F : FnMut ( ) -> capnp:: Result < C > ,
29
+ F : ' static ,
30
+ C : FromClientHook ,
31
+ {
32
+ fn get_current ( & mut self ) -> Box < dyn ClientHook > {
33
+ if let Some ( hook) = self . current . as_ref ( ) {
34
+ hook. add_ref ( )
35
+ } else {
36
+ let hook = match ( self . connect ) ( ) {
37
+ Ok ( hook) => hook. into_client_hook ( ) ,
38
+ Err ( err) => {
39
+ crate :: broken:: new_cap ( err)
40
+ }
41
+ } ;
42
+ self . current = Some ( hook. add_ref ( ) ) ;
43
+ hook
44
+ }
45
+ }
46
+ }
47
+
48
+ struct Client < F , C > {
49
+ inner : Rc < RefCell < ClientInner < F , C > > > ,
50
+ }
51
+
52
+ impl < F , C > Client < F , C >
53
+ where F : FnMut ( ) -> capnp:: Result < C > ,
54
+ F : ' static ,
55
+ C : FromClientHook ,
56
+ C : ' static ,
57
+ {
58
+ pub fn new ( connect : F ) -> Client < F , C > {
59
+ Client {
60
+ inner : Rc :: new ( RefCell :: new ( ClientInner {
61
+ connect,
62
+ generation : 0 ,
63
+ current : None ,
64
+ marker : PhantomData ,
65
+ } ) )
66
+ }
67
+ }
68
+
69
+ pub fn get_current ( & self ) -> Box < dyn ClientHook > {
70
+ self . inner . borrow_mut ( ) . get_current ( )
71
+ }
72
+
73
+ fn wrap < T : ' static > ( & self , promise : Promise < T , capnp:: Error > ) -> Promise < T , capnp:: Error >
74
+ {
75
+ let c = self . clone ( ) ;
76
+ let generation = self . inner . borrow ( ) . generation ;
77
+ Promise :: from_future ( promise. map_err ( move |err| {
78
+ if err. kind == capnp:: ErrorKind :: Disconnected
79
+ && generation == c. inner . borrow ( ) . generation
80
+ {
81
+ let mut inner = c. inner . borrow_mut ( ) ;
82
+ inner. generation = generation + 1 ;
83
+ match ( inner. connect ) ( ) {
84
+ Ok ( hook) => {
85
+ inner. current = Some ( hook. into_client_hook ( ) )
86
+ }
87
+ Err ( err) => inner. current = Some ( crate :: broken:: new_cap ( err) ) ,
88
+ }
89
+ }
90
+ err
91
+ } ) )
92
+ }
93
+ }
94
+
95
+ impl < F : ' static , C > SetTarget < C > for Client < F , C >
96
+ where F : ' static ,
97
+ C : FromClientHook ,
98
+ C : ' static ,
99
+ {
100
+ fn add_ref ( & self ) -> Box < dyn SetTarget < C > > {
101
+ Box :: new ( self . clone ( ) )
102
+ }
103
+
104
+ fn set_target ( & self , target : C ) {
105
+ self . inner . borrow_mut ( ) . current = Some ( target. into_client_hook ( ) ) ;
106
+ }
107
+ }
108
+
109
+ impl < F , C > Clone for Client < F , C > {
110
+ fn clone ( & self ) -> Self {
111
+ Self { inner : self . inner . clone ( ) }
112
+ }
113
+ }
114
+
115
+ impl < F , C > ClientHook for Client < F , C >
116
+ where F : FnMut ( ) -> capnp:: Result < C > ,
117
+ F : ' static ,
118
+ C : FromClientHook ,
119
+ C : ' static ,
120
+ {
121
+ fn add_ref ( & self ) -> Box < dyn ClientHook > {
122
+ Box :: new ( self . clone ( ) )
123
+ }
124
+
125
+ fn new_call ( & self ,
126
+ interface_id : u64 ,
127
+ method_id : u16 ,
128
+ size_hint : Option < capnp:: MessageSize > )
129
+ -> capnp:: capability:: Request < capnp:: any_pointer:: Owned , capnp:: any_pointer:: Owned >
130
+ {
131
+ let result = self . get_current ( ) . new_call ( interface_id, method_id, size_hint) ;
132
+ let hook = Request :: new ( self . clone ( ) , result. hook ) ;
133
+ capnp:: capability:: Request :: new ( Box :: new ( hook) )
134
+ }
135
+
136
+ fn call ( & self , interface_id : u64 , method_id : u16 ,
137
+ params : Box < dyn capnp:: private:: capability:: ParamsHook > ,
138
+ results : Box < dyn capnp:: private:: capability:: ResultsHook > )
139
+ -> Promise < ( ) , capnp:: Error >
140
+ {
141
+ let result = self . get_current ( ) . call ( interface_id, method_id, params, results) ;
142
+ self . wrap ( result)
143
+ }
144
+
145
+ fn get_brand ( & self ) -> usize {
146
+ 0
147
+ }
148
+
149
+ fn get_ptr ( & self ) -> usize {
150
+ ( self . inner . as_ref ( ) ) as * const _ as usize
151
+ }
152
+
153
+ fn get_resolved ( & self ) -> Option < Box < dyn ClientHook > > {
154
+ None
155
+ }
156
+
157
+ fn when_more_resolved ( & self ) -> Option < Promise < Box < dyn ClientHook > , capnp:: Error > > {
158
+ None
159
+ }
160
+
161
+ fn when_resolved ( & self ) -> Promise < ( ) , capnp:: Error > {
162
+ Promise :: ok ( ( ) )
163
+ }
164
+ }
165
+
166
+ struct Request < F , C > {
167
+ parent : Client < F , C > ,
168
+ inner : Box < dyn RequestHook > ,
169
+ }
170
+
171
+ impl < F , C > Request < F , C > {
172
+ fn new ( parent : Client < F , C > , inner : Box < dyn RequestHook > ) -> Request < F , C > {
173
+ Request { parent, inner }
174
+ }
175
+ }
176
+
177
+ impl < F , C > RequestHook for Request < F , C >
178
+ where F : FnMut ( ) -> capnp:: Result < C > ,
179
+ F : ' static ,
180
+ C : FromClientHook ,
181
+ C : ' static ,
182
+ {
183
+ fn get ( & mut self ) -> capnp:: any_pointer:: Builder < ' _ > {
184
+ self . inner . get ( )
185
+ }
186
+
187
+ fn get_brand ( & self ) -> usize {
188
+ 0
189
+ }
190
+
191
+ fn send ( self : Box < Self > ) -> capnp:: capability:: RemotePromise < capnp:: any_pointer:: Owned > {
192
+ let parent = self . parent ;
193
+ let mut result = self . inner . send ( ) ;
194
+ result. promise = parent. wrap ( result. promise ) ;
195
+ result
196
+ }
197
+
198
+ fn tail_send ( self : Box < Self > )
199
+ -> Option < ( u32 , Promise < ( ) , capnp:: Error > , Box < dyn capnp:: private:: capability:: PipelineHook > ) > {
200
+ todo ! ( )
201
+ }
202
+ }
203
+
204
+ pub fn auto_reconnect < F , C > ( mut connect : F ) -> capnp:: Result < ( C , Box < dyn SetTarget < C > > ) >
205
+ where F : FnMut ( ) -> capnp:: Result < C > ,
206
+ F : ' static ,
207
+ C : FromClientHook ,
208
+ C : ' static ,
209
+ {
210
+ let current = connect ( ) ?;
211
+ let c = Client :: new ( connect) ;
212
+ c. set_target ( current) ;
213
+ let hook : Box < dyn ClientHook > = Box :: new ( c. clone ( ) ) ;
214
+ Ok ( ( FromClientHook :: new ( hook) , Box :: new ( c) ) )
215
+ }
216
+
217
+
218
+ pub fn lazy_auto_reconnect < F , C > ( connect : F ) -> ( C , Box < dyn SetTarget < C > > )
219
+ where F : FnMut ( ) -> capnp:: Result < C > ,
220
+ F : ' static ,
221
+ C : FromClientHook ,
222
+ C : ' static ,
223
+ {
224
+ let c : Client < F , C > = Client :: new ( connect) ;
225
+ let hook : Box < dyn ClientHook > = Box :: new ( c. clone ( ) ) ;
226
+ ( FromClientHook :: new ( hook) , Box :: new ( c) )
227
+ }
0 commit comments