spikard 0.8.2 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -10
  3. data/ext/spikard_rb/Cargo.lock +234 -162
  4. data/ext/spikard_rb/Cargo.toml +3 -3
  5. data/ext/spikard_rb/extconf.rb +4 -3
  6. data/lib/spikard/config.rb +88 -12
  7. data/lib/spikard/testing.rb +3 -1
  8. data/lib/spikard/version.rb +1 -1
  9. data/lib/spikard.rb +11 -0
  10. data/vendor/crates/spikard-bindings-shared/Cargo.toml +11 -6
  11. data/vendor/crates/spikard-bindings-shared/examples/config_extraction.rs +8 -8
  12. data/vendor/crates/spikard-bindings-shared/src/config_extractor.rs +63 -25
  13. data/vendor/crates/spikard-bindings-shared/src/conversion_traits.rs +20 -4
  14. data/vendor/crates/spikard-bindings-shared/src/di_traits.rs +10 -4
  15. data/vendor/crates/spikard-bindings-shared/src/error_response.rs +25 -22
  16. data/vendor/crates/spikard-bindings-shared/src/grpc_metadata.rs +14 -12
  17. data/vendor/crates/spikard-bindings-shared/src/handler_base.rs +24 -10
  18. data/vendor/crates/spikard-bindings-shared/src/json_conversion.rs +829 -0
  19. data/vendor/crates/spikard-bindings-shared/src/lazy_cache.rs +587 -0
  20. data/vendor/crates/spikard-bindings-shared/src/lib.rs +7 -0
  21. data/vendor/crates/spikard-bindings-shared/src/lifecycle_base.rs +17 -11
  22. data/vendor/crates/spikard-bindings-shared/src/lifecycle_executor.rs +51 -73
  23. data/vendor/crates/spikard-bindings-shared/src/response_builder.rs +442 -4
  24. data/vendor/crates/spikard-bindings-shared/src/response_interpreter.rs +944 -0
  25. data/vendor/crates/spikard-bindings-shared/src/test_client_base.rs +22 -10
  26. data/vendor/crates/spikard-bindings-shared/src/validation_helpers.rs +28 -10
  27. data/vendor/crates/spikard-bindings-shared/tests/config_extractor_behavior.rs +3 -2
  28. data/vendor/crates/spikard-bindings-shared/tests/error_response_edge_cases.rs +13 -13
  29. data/vendor/crates/spikard-bindings-shared/tests/{comprehensive_coverage.rs → full_coverage.rs} +10 -5
  30. data/vendor/crates/spikard-bindings-shared/tests/handler_base_integration.rs +14 -14
  31. data/vendor/crates/spikard-bindings-shared/tests/integration_tests.rs +669 -0
  32. data/vendor/crates/spikard-core/Cargo.toml +11 -3
  33. data/vendor/crates/spikard-core/src/bindings/response.rs +6 -9
  34. data/vendor/crates/spikard-core/src/debug.rs +2 -2
  35. data/vendor/crates/spikard-core/src/di/container.rs +2 -2
  36. data/vendor/crates/spikard-core/src/di/error.rs +1 -1
  37. data/vendor/crates/spikard-core/src/di/factory.rs +9 -5
  38. data/vendor/crates/spikard-core/src/di/graph.rs +1 -0
  39. data/vendor/crates/spikard-core/src/di/resolved.rs +25 -2
  40. data/vendor/crates/spikard-core/src/di/value.rs +2 -1
  41. data/vendor/crates/spikard-core/src/errors.rs +3 -0
  42. data/vendor/crates/spikard-core/src/http.rs +94 -18
  43. data/vendor/crates/spikard-core/src/lifecycle.rs +85 -61
  44. data/vendor/crates/spikard-core/src/parameters.rs +75 -54
  45. data/vendor/crates/spikard-core/src/problem.rs +19 -5
  46. data/vendor/crates/spikard-core/src/request_data.rs +16 -24
  47. data/vendor/crates/spikard-core/src/router.rs +26 -6
  48. data/vendor/crates/spikard-core/src/schema_registry.rs +25 -11
  49. data/vendor/crates/spikard-core/src/type_hints.rs +14 -7
  50. data/vendor/crates/spikard-core/src/validation/error_mapper.rs +30 -16
  51. data/vendor/crates/spikard-core/src/validation/mod.rs +46 -33
  52. data/vendor/crates/spikard-core/tests/di_dependency_defaults.rs +1 -1
  53. data/vendor/crates/spikard-core/tests/error_mapper.rs +2 -2
  54. data/vendor/crates/spikard-core/tests/parameters_edge_cases.rs +1 -1
  55. data/vendor/crates/spikard-core/tests/parameters_full.rs +1 -1
  56. data/vendor/crates/spikard-core/tests/parameters_schema_and_formats.rs +1 -1
  57. data/vendor/crates/spikard-core/tests/validation_coverage.rs +4 -4
  58. data/vendor/crates/spikard-http/Cargo.toml +11 -2
  59. data/vendor/crates/spikard-http/src/cors.rs +32 -11
  60. data/vendor/crates/spikard-http/src/di_handler.rs +12 -8
  61. data/vendor/crates/spikard-http/src/grpc/framing.rs +469 -0
  62. data/vendor/crates/spikard-http/src/grpc/handler.rs +887 -25
  63. data/vendor/crates/spikard-http/src/grpc/mod.rs +114 -22
  64. data/vendor/crates/spikard-http/src/grpc/service.rs +232 -2
  65. data/vendor/crates/spikard-http/src/grpc/streaming.rs +80 -2
  66. data/vendor/crates/spikard-http/src/handler_trait.rs +204 -27
  67. data/vendor/crates/spikard-http/src/handler_trait_tests.rs +15 -15
  68. data/vendor/crates/spikard-http/src/jsonrpc/http_handler.rs +2 -2
  69. data/vendor/crates/spikard-http/src/jsonrpc/router.rs +2 -2
  70. data/vendor/crates/spikard-http/src/lib.rs +1 -1
  71. data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +2 -2
  72. data/vendor/crates/spikard-http/src/lifecycle.rs +4 -4
  73. data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +2 -0
  74. data/vendor/crates/spikard-http/src/server/fast_router.rs +186 -0
  75. data/vendor/crates/spikard-http/src/server/grpc_routing.rs +324 -23
  76. data/vendor/crates/spikard-http/src/server/handler.rs +33 -22
  77. data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +21 -2
  78. data/vendor/crates/spikard-http/src/server/mod.rs +125 -20
  79. data/vendor/crates/spikard-http/src/server/request_extraction.rs +126 -44
  80. data/vendor/crates/spikard-http/src/server/routing_factory.rs +80 -69
  81. data/vendor/crates/spikard-http/tests/common/handlers.rs +2 -2
  82. data/vendor/crates/spikard-http/tests/common/test_builders.rs +12 -12
  83. data/vendor/crates/spikard-http/tests/di_handler_error_responses.rs +2 -2
  84. data/vendor/crates/spikard-http/tests/di_integration.rs +6 -6
  85. data/vendor/crates/spikard-http/tests/grpc_bidirectional_streaming.rs +430 -0
  86. data/vendor/crates/spikard-http/tests/grpc_client_streaming.rs +738 -0
  87. data/vendor/crates/spikard-http/tests/grpc_integration_test.rs +13 -9
  88. data/vendor/crates/spikard-http/tests/grpc_server_streaming.rs +974 -0
  89. data/vendor/crates/spikard-http/tests/lifecycle_execution.rs +2 -2
  90. data/vendor/crates/spikard-http/tests/request_extraction_full.rs +4 -4
  91. data/vendor/crates/spikard-http/tests/server_config_builder.rs +2 -2
  92. data/vendor/crates/spikard-http/tests/server_cors_preflight.rs +1 -0
  93. data/vendor/crates/spikard-http/tests/server_openapi_jsonrpc_static.rs +140 -0
  94. data/vendor/crates/spikard-rb/Cargo.toml +11 -1
  95. data/vendor/crates/spikard-rb/build.rs +1 -0
  96. data/vendor/crates/spikard-rb/src/conversion.rs +138 -4
  97. data/vendor/crates/spikard-rb/src/grpc/handler.rs +706 -229
  98. data/vendor/crates/spikard-rb/src/grpc/mod.rs +6 -2
  99. data/vendor/crates/spikard-rb/src/gvl.rs +2 -2
  100. data/vendor/crates/spikard-rb/src/handler.rs +169 -91
  101. data/vendor/crates/spikard-rb/src/lib.rs +502 -62
  102. data/vendor/crates/spikard-rb/src/lifecycle.rs +31 -3
  103. data/vendor/crates/spikard-rb/src/metadata/route_extraction.rs +108 -43
  104. data/vendor/crates/spikard-rb/src/request.rs +117 -20
  105. data/vendor/crates/spikard-rb/src/runtime/server_runner.rs +52 -25
  106. data/vendor/crates/spikard-rb/src/server.rs +23 -14
  107. data/vendor/crates/spikard-rb/src/testing/client.rs +5 -4
  108. data/vendor/crates/spikard-rb/src/testing/sse.rs +1 -36
  109. data/vendor/crates/spikard-rb/src/testing/websocket.rs +3 -38
  110. data/vendor/crates/spikard-rb/src/websocket.rs +32 -23
  111. data/vendor/crates/spikard-rb-macros/Cargo.toml +9 -1
  112. data/vendor/crates/spikard-rb-macros/src/lib.rs +4 -5
  113. metadata +14 -4
  114. data/vendor/bundle/ruby/3.4.0/gems/diff-lcs-1.6.2/mise.toml +0 -5
  115. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.10.0/build/buildkitd.toml +0 -2
@@ -29,10 +29,10 @@ pub trait NativeLifecycleHook<Req, Resp>: Send + Sync {
29
29
  fn name(&self) -> &str;
30
30
 
31
31
  /// Execute hook with a request
32
- fn execute_request<'a>(&'a self, req: Req) -> RequestHookFutureSend<'a, Req, Resp>;
32
+ fn execute_request<'a>(&self, req: Req) -> RequestHookFutureSend<'a, Req, Resp>;
33
33
 
34
34
  /// Execute hook with a response
35
- fn execute_response<'a>(&'a self, resp: Resp) -> ResponseHookFutureSend<'a, Resp>;
35
+ fn execute_response<'a>(&self, resp: Resp) -> ResponseHookFutureSend<'a, Resp>;
36
36
  }
37
37
 
38
38
  /// Trait for lifecycle hooks on local (wasm) targets (no Send requirements).
@@ -41,10 +41,10 @@ pub trait LocalLifecycleHook<Req, Resp> {
41
41
  fn name(&self) -> &str;
42
42
 
43
43
  /// Execute hook with a request
44
- fn execute_request<'a>(&'a self, req: Req) -> RequestHookFutureLocal<'a, Req, Resp>;
44
+ fn execute_request<'a>(&self, req: Req) -> RequestHookFutureLocal<'a, Req, Resp>;
45
45
 
46
46
  /// Execute hook with a response
47
- fn execute_response<'a>(&'a self, resp: Resp) -> ResponseHookFutureLocal<'a, Resp>;
47
+ fn execute_response<'a>(&self, resp: Resp) -> ResponseHookFutureLocal<'a, Resp>;
48
48
  }
49
49
 
50
50
  #[cfg(target_arch = "wasm32")]
@@ -97,17 +97,19 @@ impl<Req, Resp> std::fmt::Debug for LifecycleHooks<Req, Resp> {
97
97
 
98
98
  impl<Req, Resp> LifecycleHooks<Req, Resp> {
99
99
  /// Create a new empty hooks container
100
+ #[must_use]
100
101
  pub fn new() -> Self {
101
102
  Self::default()
102
103
  }
103
104
 
104
105
  /// Builder constructor for ergonomic hook registration
106
+ #[must_use]
105
107
  pub fn builder() -> LifecycleHooksBuilder<Req, Resp> {
106
108
  LifecycleHooksBuilder::new()
107
109
  }
108
110
 
109
111
  /// Check if any hooks are registered
110
- #[inline(always)]
112
+ #[must_use]
111
113
  pub fn is_empty(&self) -> bool {
112
114
  self.on_request.is_empty()
113
115
  && self.pre_validation.is_empty()
@@ -136,6 +138,8 @@ impl<Req, Resp> LifecycleHooks<Req, Resp> {
136
138
  self.on_error.push(hook);
137
139
  }
138
140
 
141
+ /// # Errors
142
+ /// Returns an error string if a hook execution fails.
139
143
  pub async fn execute_on_request(&self, mut req: Req) -> Result<HookResult<Req, Resp>, String> {
140
144
  if self.on_request.is_empty() {
141
145
  return Ok(HookResult::Continue(req));
@@ -151,6 +155,8 @@ impl<Req, Resp> LifecycleHooks<Req, Resp> {
151
155
  Ok(HookResult::Continue(req))
152
156
  }
153
157
 
158
+ /// # Errors
159
+ /// Returns an error string if a hook execution fails.
154
160
  pub async fn execute_pre_validation(&self, mut req: Req) -> Result<HookResult<Req, Resp>, String> {
155
161
  if self.pre_validation.is_empty() {
156
162
  return Ok(HookResult::Continue(req));
@@ -166,6 +172,8 @@ impl<Req, Resp> LifecycleHooks<Req, Resp> {
166
172
  Ok(HookResult::Continue(req))
167
173
  }
168
174
 
175
+ /// # Errors
176
+ /// Returns an error string if a hook execution fails.
169
177
  pub async fn execute_pre_handler(&self, mut req: Req) -> Result<HookResult<Req, Resp>, String> {
170
178
  if self.pre_handler.is_empty() {
171
179
  return Ok(HookResult::Continue(req));
@@ -181,6 +189,8 @@ impl<Req, Resp> LifecycleHooks<Req, Resp> {
181
189
  Ok(HookResult::Continue(req))
182
190
  }
183
191
 
192
+ /// # Errors
193
+ /// Returns an error string if a hook execution fails.
184
194
  pub async fn execute_on_response(&self, mut resp: Resp) -> Result<Resp, String> {
185
195
  if self.on_response.is_empty() {
186
196
  return Ok(resp);
@@ -188,14 +198,15 @@ impl<Req, Resp> LifecycleHooks<Req, Resp> {
188
198
 
189
199
  for hook in &self.on_response {
190
200
  match hook.execute_response(resp).await? {
191
- HookResult::Continue(r) => resp = r,
192
- HookResult::ShortCircuit(r) => resp = r,
201
+ HookResult::Continue(r) | HookResult::ShortCircuit(r) => resp = r,
193
202
  }
194
203
  }
195
204
 
196
205
  Ok(resp)
197
206
  }
198
207
 
208
+ /// # Errors
209
+ /// Returns an error string if a hook execution fails.
199
210
  pub async fn execute_on_error(&self, mut resp: Resp) -> Result<Resp, String> {
200
211
  if self.on_error.is_empty() {
201
212
  return Ok(resp);
@@ -203,8 +214,7 @@ impl<Req, Resp> LifecycleHooks<Req, Resp> {
203
214
 
204
215
  for hook in &self.on_error {
205
216
  match hook.execute_response(resp).await? {
206
- HookResult::Continue(r) => resp = r,
207
- HookResult::ShortCircuit(r) => resp = r,
217
+ HookResult::Continue(r) | HookResult::ShortCircuit(r) => resp = r,
208
218
  }
209
219
  }
210
220
 
@@ -237,11 +247,11 @@ where
237
247
  &self.name
238
248
  }
239
249
 
240
- fn execute_request<'a>(&'a self, req: Req) -> RequestHookFutureSend<'a, Req, Resp> {
250
+ fn execute_request<'a>(&self, req: Req) -> RequestHookFutureSend<'a, Req, Resp> {
241
251
  Box::pin((self.func)(req))
242
252
  }
243
253
 
244
- fn execute_response<'a>(&'a self, _resp: Resp) -> ResponseHookFutureSend<'a, Resp> {
254
+ fn execute_response<'a>(&self, _resp: Resp) -> ResponseHookFutureSend<'a, Resp> {
245
255
  Box::pin(async move { Err("Request hook called with response - this is a bug".to_string()) })
246
256
  }
247
257
  }
@@ -258,11 +268,11 @@ where
258
268
  &self.name
259
269
  }
260
270
 
261
- fn execute_request<'a>(&'a self, req: Req) -> RequestHookFutureLocal<'a, Req, Resp> {
271
+ fn execute_request<'a>(&self, req: Req) -> RequestHookFutureLocal<'a, Req, Resp> {
262
272
  Box::pin((self.func)(req))
263
273
  }
264
274
 
265
- fn execute_response<'a>(&'a self, _resp: Resp) -> ResponseHookFutureLocal<'a, Resp> {
275
+ fn execute_response<'a>(&self, _resp: Resp) -> ResponseHookFutureLocal<'a, Resp> {
266
276
  Box::pin(async move { Err("Request hook called with response - this is a bug".to_string()) })
267
277
  }
268
278
  }
@@ -279,11 +289,11 @@ where
279
289
  &self.name
280
290
  }
281
291
 
282
- fn execute_request<'a>(&'a self, _req: Req) -> RequestHookFutureSend<'a, Req, Resp> {
292
+ fn execute_request<'a>(&self, _req: Req) -> RequestHookFutureSend<'a, Req, Resp> {
283
293
  Box::pin(async move { Err("Response hook called with request - this is a bug".to_string()) })
284
294
  }
285
295
 
286
- fn execute_response<'a>(&'a self, resp: Resp) -> ResponseHookFutureSend<'a, Resp> {
296
+ fn execute_response<'a>(&self, resp: Resp) -> ResponseHookFutureSend<'a, Resp> {
287
297
  Box::pin((self.func)(resp))
288
298
  }
289
299
  }
@@ -300,52 +310,66 @@ where
300
310
  &self.name
301
311
  }
302
312
 
303
- fn execute_request<'a>(&'a self, _req: Req) -> RequestHookFutureLocal<'a, Req, Resp> {
313
+ fn execute_request<'a>(&self, _req: Req) -> RequestHookFutureLocal<'a, Req, Resp> {
304
314
  Box::pin(async move { Err("Response hook called with request - this is a bug".to_string()) })
305
315
  }
306
316
 
307
- fn execute_response<'a>(&'a self, resp: Resp) -> ResponseHookFutureLocal<'a, Resp> {
317
+ fn execute_response<'a>(&self, resp: Resp) -> ResponseHookFutureLocal<'a, Resp> {
308
318
  Box::pin((self.func)(resp))
309
319
  }
310
320
  }
311
321
 
312
- /// Builder Pattern for LifecycleHooks
322
+ /// Builder pattern for `LifecycleHooks`
313
323
  pub struct LifecycleHooksBuilder<Req, Resp> {
314
324
  hooks: LifecycleHooks<Req, Resp>,
315
325
  }
316
326
 
317
327
  impl<Req, Resp> LifecycleHooksBuilder<Req, Resp> {
328
+ /// Create a new builder
329
+ #[must_use]
318
330
  pub fn new() -> Self {
319
331
  Self {
320
332
  hooks: LifecycleHooks::default(),
321
333
  }
322
334
  }
323
335
 
336
+ /// Add an `on_request` hook
337
+ #[must_use]
324
338
  pub fn on_request(mut self, hook: Arc<CoreHook<Req, Resp>>) -> Self {
325
339
  self.hooks.add_on_request(hook);
326
340
  self
327
341
  }
328
342
 
343
+ /// Add a `pre_validation` hook
344
+ #[must_use]
329
345
  pub fn pre_validation(mut self, hook: Arc<CoreHook<Req, Resp>>) -> Self {
330
346
  self.hooks.add_pre_validation(hook);
331
347
  self
332
348
  }
333
349
 
350
+ /// Add a `pre_handler` hook
351
+ #[must_use]
334
352
  pub fn pre_handler(mut self, hook: Arc<CoreHook<Req, Resp>>) -> Self {
335
353
  self.hooks.add_pre_handler(hook);
336
354
  self
337
355
  }
338
356
 
357
+ /// Add an `on_response` hook
358
+ #[must_use]
339
359
  pub fn on_response(mut self, hook: Arc<CoreHook<Req, Resp>>) -> Self {
340
360
  self.hooks.add_on_response(hook);
341
361
  self
342
362
  }
343
363
 
364
+ /// Add an `on_error` hook
365
+ #[must_use]
344
366
  pub fn on_error(mut self, hook: Arc<CoreHook<Req, Resp>>) -> Self {
345
367
  self.hooks.add_on_error(hook);
346
368
  self
347
369
  }
348
370
 
371
+ /// Build the `LifecycleHooks` instance
372
+ #[must_use]
349
373
  pub fn build(self) -> LifecycleHooks<Req, Resp> {
350
374
  self.hooks
351
375
  }
@@ -441,11 +465,11 @@ mod tests {
441
465
  #[test]
442
466
  fn test_hook_result_debug_format() {
443
467
  let continue_result: HookResult<i32, String> = HookResult::Continue(100);
444
- let debug_str = format!("{:?}", continue_result);
468
+ let debug_str = format!("{continue_result:?}");
445
469
  assert!(debug_str.contains("Continue"));
446
470
 
447
471
  let short_circuit_result: HookResult<i32, String> = HookResult::ShortCircuit("err".to_string());
448
- let debug_str = format!("{:?}", short_circuit_result);
472
+ let debug_str = format!("{short_circuit_result:?}");
449
473
  assert!(debug_str.contains("ShortCircuit"));
450
474
  }
451
475
 
@@ -470,16 +494,16 @@ mod tests {
470
494
  #[test]
471
495
  fn test_lifecycle_hooks_debug_format_empty() {
472
496
  let hooks: LifecycleHooks<String, String> = LifecycleHooks::default();
473
- let debug_str = format!("{:?}", hooks);
497
+ let debug_str = format!("{hooks:?}");
474
498
  assert!(debug_str.contains("LifecycleHooks"));
475
499
  assert!(debug_str.contains("on_request_count"));
476
- assert!(debug_str.contains("0"));
500
+ assert!(debug_str.contains('0'));
477
501
  }
478
502
 
479
503
  #[test]
480
504
  fn test_lifecycle_hooks_clone() {
481
505
  let hooks1: LifecycleHooks<String, String> = LifecycleHooks::default();
482
- let hooks2 = hooks1.clone();
506
+ let hooks2 = hooks1;
483
507
  assert!(hooks2.is_empty());
484
508
  }
485
509
 
@@ -542,15 +566,15 @@ mod tests {
542
566
 
543
567
  #[cfg(not(target_arch = "wasm32"))]
544
568
  impl NativeLifecycleHook<String, String> for TestRequestHook {
545
- fn name(&self) -> &str {
569
+ fn name(&self) -> &'static str {
546
570
  "test_request_hook"
547
571
  }
548
572
 
549
- fn execute_request<'a>(&'a self, req: String) -> RequestHookFutureSend<'a, String, String> {
573
+ fn execute_request<'a>(&self, req: String) -> RequestHookFutureSend<'a, String, String> {
550
574
  Box::pin(async move { Ok(HookResult::Continue(req + "_modified")) })
551
575
  }
552
576
 
553
- fn execute_response<'a>(&'a self, _resp: String) -> ResponseHookFutureSend<'a, String> {
577
+ fn execute_response<'a>(&self, _resp: String) -> ResponseHookFutureSend<'a, String> {
554
578
  Box::pin(async { Err("not implemented".to_string()) })
555
579
  }
556
580
  }
@@ -564,11 +588,11 @@ mod tests {
564
588
  "test_request_hook"
565
589
  }
566
590
 
567
- fn execute_request<'a>(&'a self, req: String) -> RequestHookFutureLocal<'a, String, String> {
591
+ fn execute_request<'a>(&self, req: String) -> RequestHookFutureLocal<'a, String, String> {
568
592
  Box::pin(async move { Ok(HookResult::Continue(req + "_modified")) })
569
593
  }
570
594
 
571
- fn execute_response<'a>(&'a self, _resp: String) -> ResponseHookFutureLocal<'a, String> {
595
+ fn execute_response<'a>(&self, _resp: String) -> ResponseHookFutureLocal<'a, String> {
572
596
  Box::pin(async { Err("not implemented".to_string()) })
573
597
  }
574
598
  }
@@ -604,15 +628,15 @@ mod tests {
604
628
 
605
629
  #[cfg(not(target_arch = "wasm32"))]
606
630
  impl NativeLifecycleHook<String, String> for TestResponseHook {
607
- fn name(&self) -> &str {
631
+ fn name(&self) -> &'static str {
608
632
  "test_response_hook"
609
633
  }
610
634
 
611
- fn execute_request<'a>(&'a self, _req: String) -> RequestHookFutureSend<'a, String, String> {
635
+ fn execute_request<'a>(&self, _req: String) -> RequestHookFutureSend<'a, String, String> {
612
636
  Box::pin(async { Err("not implemented".to_string()) })
613
637
  }
614
638
 
615
- fn execute_response<'a>(&'a self, resp: String) -> ResponseHookFutureSend<'a, String> {
639
+ fn execute_response<'a>(&self, resp: String) -> ResponseHookFutureSend<'a, String> {
616
640
  Box::pin(async move { Ok(HookResult::Continue(resp + "_processed")) })
617
641
  }
618
642
  }
@@ -626,11 +650,11 @@ mod tests {
626
650
  "test_response_hook"
627
651
  }
628
652
 
629
- fn execute_request<'a>(&'a self, _req: String) -> RequestHookFutureLocal<'a, String, String> {
653
+ fn execute_request<'a>(&self, _req: String) -> RequestHookFutureLocal<'a, String, String> {
630
654
  Box::pin(async { Err("not implemented".to_string()) })
631
655
  }
632
656
 
633
- fn execute_response<'a>(&'a self, resp: String) -> ResponseHookFutureLocal<'a, String> {
657
+ fn execute_response<'a>(&self, resp: String) -> ResponseHookFutureLocal<'a, String> {
634
658
  Box::pin(async move { Ok(HookResult::Continue(resp + "_processed")) })
635
659
  }
636
660
  }
@@ -759,15 +783,15 @@ mod tests {
759
783
 
760
784
  #[cfg(not(target_arch = "wasm32"))]
761
785
  impl NativeLifecycleHook<String, String> for TestShortCircuitHook {
762
- fn name(&self) -> &str {
786
+ fn name(&self) -> &'static str {
763
787
  "short_circuit"
764
788
  }
765
789
 
766
- fn execute_request<'a>(&'a self, _req: String) -> RequestHookFutureSend<'a, String, String> {
790
+ fn execute_request<'a>(&self, _req: String) -> RequestHookFutureSend<'a, String, String> {
767
791
  Box::pin(async { Ok(HookResult::ShortCircuit("short_circuit_response".to_string())) })
768
792
  }
769
793
 
770
- fn execute_response<'a>(&'a self, _resp: String) -> ResponseHookFutureSend<'a, String> {
794
+ fn execute_response<'a>(&self, _resp: String) -> ResponseHookFutureSend<'a, String> {
771
795
  Box::pin(async { Err("not implemented".to_string()) })
772
796
  }
773
797
  }
@@ -781,11 +805,11 @@ mod tests {
781
805
  "short_circuit"
782
806
  }
783
807
 
784
- fn execute_request<'a>(&'a self, _req: String) -> RequestHookFutureLocal<'a, String, String> {
808
+ fn execute_request<'a>(&self, _req: String) -> RequestHookFutureLocal<'a, String, String> {
785
809
  Box::pin(async { Ok(HookResult::ShortCircuit("short_circuit_response".to_string())) })
786
810
  }
787
811
 
788
- fn execute_response<'a>(&'a self, _resp: String) -> ResponseHookFutureLocal<'a, String> {
812
+ fn execute_response<'a>(&self, _resp: String) -> ResponseHookFutureLocal<'a, String> {
789
813
  Box::pin(async { Err("not implemented".to_string()) })
790
814
  }
791
815
  }
@@ -834,15 +858,15 @@ mod tests {
834
858
 
835
859
  #[cfg(not(target_arch = "wasm32"))]
836
860
  impl NativeLifecycleHook<String, String> for TestResponseShortCircuitHook {
837
- fn name(&self) -> &str {
861
+ fn name(&self) -> &'static str {
838
862
  "response_short_circuit"
839
863
  }
840
864
 
841
- fn execute_request<'a>(&'a self, _req: String) -> RequestHookFutureSend<'a, String, String> {
865
+ fn execute_request<'a>(&self, _req: String) -> RequestHookFutureSend<'a, String, String> {
842
866
  Box::pin(async { Err("not implemented".to_string()) })
843
867
  }
844
868
 
845
- fn execute_response<'a>(&'a self, resp: String) -> ResponseHookFutureSend<'a, String> {
869
+ fn execute_response<'a>(&self, resp: String) -> ResponseHookFutureSend<'a, String> {
846
870
  Box::pin(async move { Ok(HookResult::ShortCircuit("short_circuit_".to_string() + &resp)) })
847
871
  }
848
872
  }
@@ -856,11 +880,11 @@ mod tests {
856
880
  "response_short_circuit"
857
881
  }
858
882
 
859
- fn execute_request<'a>(&'a self, _req: String) -> RequestHookFutureLocal<'a, String, String> {
883
+ fn execute_request<'a>(&self, _req: String) -> RequestHookFutureLocal<'a, String, String> {
860
884
  Box::pin(async { Err("not implemented".to_string()) })
861
885
  }
862
886
 
863
- fn execute_response<'a>(&'a self, resp: String) -> ResponseHookFutureLocal<'a, String> {
887
+ fn execute_response<'a>(&self, resp: String) -> ResponseHookFutureLocal<'a, String> {
864
888
  Box::pin(async move { Ok(HookResult::ShortCircuit("short_circuit_".to_string() + &resp)) })
865
889
  }
866
890
  }
@@ -914,16 +938,16 @@ mod tests {
914
938
 
915
939
  #[cfg(not(target_arch = "wasm32"))]
916
940
  impl NativeLifecycleHook<String, String> for TestAppendHook {
917
- fn name(&self) -> &str {
941
+ fn name(&self) -> &'static str {
918
942
  "append"
919
943
  }
920
944
 
921
- fn execute_request<'a>(&'a self, req: String) -> RequestHookFutureSend<'a, String, String> {
945
+ fn execute_request<'a>(&self, req: String) -> RequestHookFutureSend<'a, String, String> {
922
946
  let suffix = self.0;
923
947
  Box::pin(async move { Ok(HookResult::Continue(req + suffix)) })
924
948
  }
925
949
 
926
- fn execute_response<'a>(&'a self, _resp: String) -> ResponseHookFutureSend<'a, String> {
950
+ fn execute_response<'a>(&self, _resp: String) -> ResponseHookFutureSend<'a, String> {
927
951
  Box::pin(async { Err("not implemented".to_string()) })
928
952
  }
929
953
  }
@@ -937,12 +961,12 @@ mod tests {
937
961
  "append"
938
962
  }
939
963
 
940
- fn execute_request<'a>(&'a self, req: String) -> RequestHookFutureLocal<'a, String, String> {
964
+ fn execute_request<'a>(&self, req: String) -> RequestHookFutureLocal<'a, String, String> {
941
965
  let suffix = self.0;
942
966
  Box::pin(async move { Ok(HookResult::Continue(req + suffix)) })
943
967
  }
944
968
 
945
- fn execute_response<'a>(&'a self, _resp: String) -> ResponseHookFutureLocal<'a, String> {
969
+ fn execute_response<'a>(&self, _resp: String) -> ResponseHookFutureLocal<'a, String> {
946
970
  Box::pin(async { Err("not implemented".to_string()) })
947
971
  }
948
972
  }
@@ -970,15 +994,15 @@ mod tests {
970
994
 
971
995
  #[cfg(not(target_arch = "wasm32"))]
972
996
  impl NativeLifecycleHook<String, String> for TestAppendResponseHook {
973
- fn name(&self) -> &str {
997
+ fn name(&self) -> &'static str {
974
998
  "append_response"
975
999
  }
976
1000
 
977
- fn execute_request<'a>(&'a self, _req: String) -> RequestHookFutureSend<'a, String, String> {
1001
+ fn execute_request<'a>(&self, _req: String) -> RequestHookFutureSend<'a, String, String> {
978
1002
  Box::pin(async { Err("not implemented".to_string()) })
979
1003
  }
980
1004
 
981
- fn execute_response<'a>(&'a self, resp: String) -> ResponseHookFutureSend<'a, String> {
1005
+ fn execute_response<'a>(&self, resp: String) -> ResponseHookFutureSend<'a, String> {
982
1006
  let suffix = self.0;
983
1007
  Box::pin(async move { Ok(HookResult::Continue(resp + suffix)) })
984
1008
  }
@@ -993,11 +1017,11 @@ mod tests {
993
1017
  "append_response"
994
1018
  }
995
1019
 
996
- fn execute_request<'a>(&'a self, _req: String) -> RequestHookFutureLocal<'a, String, String> {
1020
+ fn execute_request<'a>(&self, _req: String) -> RequestHookFutureLocal<'a, String, String> {
997
1021
  Box::pin(async { Err("not implemented".to_string()) })
998
1022
  }
999
1023
 
1000
- fn execute_response<'a>(&'a self, resp: String) -> ResponseHookFutureLocal<'a, String> {
1024
+ fn execute_response<'a>(&self, resp: String) -> ResponseHookFutureLocal<'a, String> {
1001
1025
  let suffix = self.0;
1002
1026
  Box::pin(async move { Ok(HookResult::Continue(resp + suffix)) })
1003
1027
  }
@@ -1031,15 +1055,15 @@ mod tests {
1031
1055
 
1032
1056
  #[cfg(not(target_arch = "wasm32"))]
1033
1057
  impl NativeLifecycleHook<String, String> for TestErrorHook {
1034
- fn name(&self) -> &str {
1058
+ fn name(&self) -> &'static str {
1035
1059
  "error_hook"
1036
1060
  }
1037
1061
 
1038
- fn execute_request<'a>(&'a self, _req: String) -> RequestHookFutureSend<'a, String, String> {
1062
+ fn execute_request<'a>(&self, _req: String) -> RequestHookFutureSend<'a, String, String> {
1039
1063
  Box::pin(async { Err("hook_error".to_string()) })
1040
1064
  }
1041
1065
 
1042
- fn execute_response<'a>(&'a self, _resp: String) -> ResponseHookFutureSend<'a, String> {
1066
+ fn execute_response<'a>(&self, _resp: String) -> ResponseHookFutureSend<'a, String> {
1043
1067
  Box::pin(async { Err("hook_error".to_string()) })
1044
1068
  }
1045
1069
  }
@@ -1053,11 +1077,11 @@ mod tests {
1053
1077
  "error_hook"
1054
1078
  }
1055
1079
 
1056
- fn execute_request<'a>(&'a self, _req: String) -> RequestHookFutureLocal<'a, String, String> {
1080
+ fn execute_request<'a>(&self, _req: String) -> RequestHookFutureLocal<'a, String, String> {
1057
1081
  Box::pin(async { Err("hook_error".to_string()) })
1058
1082
  }
1059
1083
 
1060
- fn execute_response<'a>(&'a self, _resp: String) -> ResponseHookFutureLocal<'a, String> {
1084
+ fn execute_response<'a>(&self, _resp: String) -> ResponseHookFutureLocal<'a, String> {
1061
1085
  Box::pin(async { Err("hook_error".to_string()) })
1062
1086
  }
1063
1087
  }
@@ -1136,9 +1160,9 @@ mod tests {
1136
1160
  #[cfg(target_arch = "wasm32")]
1137
1161
  hooks.add_on_request(Arc::new(TestRequestHookLocal));
1138
1162
 
1139
- let debug_str = format!("{:?}", hooks);
1163
+ let debug_str = format!("{hooks:?}");
1140
1164
  assert!(debug_str.contains("on_request_count"));
1141
- assert!(debug_str.contains("1"));
1165
+ assert!(debug_str.contains('1'));
1142
1166
  }
1143
1167
 
1144
1168
  #[cfg(not(target_arch = "wasm32"))]
@@ -1219,7 +1243,7 @@ mod tests {
1219
1243
  }
1220
1244
 
1221
1245
  #[test]
1222
- fn test_is_empty_comprehensive() {
1246
+ fn test_is_empty_before_and_after_adding_hooks() {
1223
1247
  let mut hooks: LifecycleHooks<String, String> = LifecycleHooks::new();
1224
1248
  assert!(hooks.is_empty());
1225
1249