@@ -73,7 +73,7 @@ pub struct Config {
73
73
74
74
/// A timeout for a remote method call.
75
75
///
76
- /// All remote method invocations through your remote object and delete requests (that happens when you drop a remote object)
76
+ /// All remote method invocations through your proxy object and delete requests (that happens when you drop a proxy object)
77
77
/// will have this timeout. If it exceeds, it will cause an error.
78
78
///
79
79
/// Use `None` for to wait indefinitely.
@@ -103,6 +103,23 @@ impl Config {
103
103
}
104
104
}
105
105
106
+ /// One end of a `remote-trait-object` connection.
107
+ ///
108
+ /// If you establish a remote-trait-object connection,
109
+ /// there must be two ends and each will be provided as a `Context` to each user on both sides.
110
+ ///
111
+ /// A context holds multiple things to function as a `remote-trait-object` connection end.
112
+ /// Since the connection is symmetric, it manages both _server_ and _client_ toward the other end.
113
+ /// It also manages a _registry_ that contains all exported services.
114
+ /// The server will look up the registry to find a target object for handling an incoming method invocation.
115
+ ///
116
+ /// Note that `remote-trait-object` is a point-to-point connection protocol.
117
+ /// Exporting & importing a service are always performed on a specific connection,
118
+ /// which is toward the other side, or another instance of `Context`.
119
+ ///
120
+ /// If you created an instance of this, that means you have a connection that has been successfully established **once**,
121
+ /// but is not guaranteed to be alive.
122
+ /// If the other end (or the other `Context`) is closed, most operations performed on `Context` will just cause an error.
106
123
pub struct Context {
107
124
config : Config ,
108
125
multiplexer : Option < Multiplexer > ,
@@ -119,6 +136,14 @@ impl std::fmt::Debug for Context {
119
136
}
120
137
121
138
impl Context {
139
+ /// Creates a new context without any initial services.
140
+ ///
141
+ /// If you decide to use this, you have to exchange raw [`HandleToExchange`] at least once using a secondary transportation means.
142
+ /// It is really rarely needed, so please consider introducing an initializing service as an initial service, to avoid any raw exchange.
143
+ ///
144
+ /// Please see [`with_initial_service()`] for a general explanation of creation of `Context`.
145
+ ///
146
+ /// [`with_initial_service()`]: ./struct.Context.html#method.with_initial_service
122
147
pub fn new < S : TransportSend + ' static , R : TransportRecv + ' static > (
123
148
config : Config ,
124
149
transport_send : S ,
@@ -130,6 +155,12 @@ impl Context {
130
155
ctx
131
156
}
132
157
158
+ /// Creates a new context only exporting a service, but importing nothing.
159
+ ///
160
+ /// The other end's context must be initialized with `with_initial_service_import()`.
161
+ /// Please see [`with_initial_service()`] for a general explanation of creation of `Context`.
162
+ ///
163
+ /// [`with_initial_service()`]: ./struct.Context.html#method.with_initial_service
133
164
pub fn with_initial_service_export < S : TransportSend + ' static , R : TransportRecv + ' static , A : ?Sized + Service > (
134
165
config : Config ,
135
166
transport_send : S ,
@@ -141,6 +172,12 @@ impl Context {
141
172
ctx
142
173
}
143
174
175
+ /// Creates a new context only importing a service, but exporting nothing.
176
+ ///
177
+ /// The other end's context must be initialized with `with_initial_service_export()`.
178
+ /// Please see [`with_initial_service()`] for a general explanation of creation of `Context`.
179
+ ///
180
+ /// [`with_initial_service()`]: ./struct.Context.html#method.with_initial_service
144
181
pub fn with_initial_service_import < S : TransportSend + ' static , R : TransportRecv + ' static , B : ?Sized + Service > (
145
182
config : Config ,
146
183
transport_send : S ,
@@ -152,6 +189,15 @@ impl Context {
152
189
( ctx, import)
153
190
}
154
191
192
+ /// Creates a new context exchanging two services, one for export and one for import.
193
+ ///
194
+ /// It takes `initial_service` and registers in it, and passes a `HandleToExchange` internally. (_export_).
195
+ /// Also it receives a `HandleToExchange` from the other side, and makes it into a proxy object. (_import_)
196
+ ///
197
+ /// The other end's context must be initialized with `with_initial_service()` as well, and
198
+ /// such processes will be symmetric for both.
199
+ ///
200
+ /// [`HandleToExchange`]: ../raw_exchange/struct.HandleToExchange.html
155
201
pub fn with_initial_service <
156
202
S : TransportSend + ' static ,
157
203
R : TransportRecv + ' static ,
@@ -204,16 +250,38 @@ impl Context {
204
250
Arc :: downgrade ( & self . port . clone ( ) . expect ( "It becomes None only when the context is dropped." ) ) as Weak < dyn Port >
205
251
}
206
252
253
+ /// Clears all service objects in its registry.
254
+ ///
255
+ /// The most usual way of deleting a service object is dropping its proxy object on the client side, and letting it request a delete to the exporter side.
256
+ /// However, in some cases (especially while you're trying to shut down the connection) it is useful to clear all exported service objects
257
+ /// **by the exporter side itself**.
258
+ ///
259
+ /// Note that it will cause an error if the client side drops a proxy object of an already deleted (by this method) service object.
260
+ /// Consider calling [`disable_garbage_collection()`] on the other end if there's such an issue.
261
+ ///
262
+ /// Note also that this might trigger _delete request_ as a side effect since the service object might own a proxy object.
263
+ ///
264
+ /// [`disable_garbage_collection()`]: ./struct.Context.html#method.disable_garbage_collection
207
265
pub fn clear_service_registry ( & mut self ) {
208
266
self . port . as_mut ( ) . unwrap ( ) . clear_registry ( ) ;
209
267
}
210
268
269
+ /// Disables all _delete request_ from this end to the other end.
270
+ ///
271
+ /// If you call this, all `drop()` of proxy objects imported from this context won't send a delete request anymore.
272
+ /// This is useful when you're not sure if the connection is still alive, but you have to close your side's context anyway.
211
273
pub fn disable_garbage_collection ( & self ) {
212
274
self . port . as_ref ( ) . expect ( "It becomes None only when the context is dropped." ) . set_no_drop ( ) ;
213
275
}
214
276
215
- /// TODO: write a good explanation
216
- /// FIXME: use timeout
277
+ /// Closes a context with a firm synchronization with the other end.
278
+ ///
279
+ /// If you call this method, it will block until the other end calls `firm_close()` too.
280
+ /// This is useful when you want to assure that two ends never suffer from 'other end has been closed' error.
281
+ /// If one of the contexts dropped too early, all remote calls (including delete request) from the other end will fail.
282
+ /// To avoid such a situation, consider using this to stay alive as long as it is required.
283
+ ///
284
+ /// FIXME: currently it doesn't use `timeout` and blocks indefinitely.
217
285
pub fn firm_close ( self , _timeout : Option < std:: time:: Duration > ) -> Result < ( ) , Self > {
218
286
let barrier = Arc :: clone ( & self . firm_close_barrier ) ;
219
287
let t = std:: thread:: spawn ( move || {
@@ -227,6 +295,7 @@ impl Context {
227
295
}
228
296
229
297
impl Drop for Context {
298
+ /// This will delete all service objects after calling `disable_garbage_collection()` internally.
230
299
fn drop ( & mut self ) {
231
300
// We have to clean all registered service, as some might hold another proxy object inside, which refers this context's port.
232
301
// For such case, we have to make them be dropped first before we unwrap the Arc<BasicPort>
0 commit comments