itsi-scheduler 0.1.5 → 0.2.2

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +120 -52
  3. data/README.md +57 -24
  4. data/Rakefile +0 -4
  5. data/ext/itsi_acme/Cargo.toml +86 -0
  6. data/ext/itsi_acme/examples/high_level.rs +63 -0
  7. data/ext/itsi_acme/examples/high_level_warp.rs +52 -0
  8. data/ext/itsi_acme/examples/low_level.rs +87 -0
  9. data/ext/itsi_acme/examples/low_level_axum.rs +66 -0
  10. data/ext/itsi_acme/src/acceptor.rs +81 -0
  11. data/ext/itsi_acme/src/acme.rs +354 -0
  12. data/ext/itsi_acme/src/axum.rs +86 -0
  13. data/ext/itsi_acme/src/cache.rs +39 -0
  14. data/ext/itsi_acme/src/caches/boxed.rs +80 -0
  15. data/ext/itsi_acme/src/caches/composite.rs +69 -0
  16. data/ext/itsi_acme/src/caches/dir.rs +106 -0
  17. data/ext/itsi_acme/src/caches/mod.rs +11 -0
  18. data/ext/itsi_acme/src/caches/no.rs +78 -0
  19. data/ext/itsi_acme/src/caches/test.rs +136 -0
  20. data/ext/itsi_acme/src/config.rs +172 -0
  21. data/ext/itsi_acme/src/https_helper.rs +69 -0
  22. data/ext/itsi_acme/src/incoming.rs +142 -0
  23. data/ext/itsi_acme/src/jose.rs +161 -0
  24. data/ext/itsi_acme/src/lib.rs +142 -0
  25. data/ext/itsi_acme/src/resolver.rs +59 -0
  26. data/ext/itsi_acme/src/state.rs +424 -0
  27. data/ext/itsi_error/Cargo.toml +1 -0
  28. data/ext/itsi_error/src/lib.rs +106 -7
  29. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  30. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  31. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  32. data/ext/itsi_error/target/debug/build/rb-sys-49f554618693db24/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
  33. data/ext/itsi_error/target/debug/incremental/itsi_error-1mmt5sux7jb0i/s-h510z7m8v9-0bxu7yd.lock +0 -0
  34. data/ext/itsi_error/target/debug/incremental/itsi_error-2vn3jey74oiw0/s-h5113n0e7e-1v5qzs6.lock +0 -0
  35. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510ykifhe-0tbnep2.lock +0 -0
  36. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510yyocpj-0tz7ug7.lock +0 -0
  37. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510z0xc8g-14ol18k.lock +0 -0
  38. data/ext/itsi_error/target/debug/incremental/itsi_error-3g5qf4y7d54uj/s-h5113n0e7d-1trk8on.lock +0 -0
  39. data/ext/itsi_error/target/debug/incremental/itsi_error-3lpfftm45d3e2/s-h510z7m8r3-1pxp20o.lock +0 -0
  40. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510ykifek-1uxasnk.lock +0 -0
  41. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510yyocki-11u37qm.lock +0 -0
  42. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510z0xc93-0pmy0zm.lock +0 -0
  43. data/ext/itsi_rb_helpers/Cargo.toml +1 -0
  44. data/ext/itsi_rb_helpers/src/heap_value.rs +18 -0
  45. data/ext/itsi_rb_helpers/src/lib.rs +63 -12
  46. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  47. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  48. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  49. data/ext/itsi_rb_helpers/target/debug/build/rb-sys-eb9ed4ff3a60f995/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
  50. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-040pxg6yhb3g3/s-h5113n7a1b-03bwlt4.lock +0 -0
  51. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h51113xnh3-1eik1ip.lock +0 -0
  52. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h5111704jj-0g4rj8x.lock +0 -0
  53. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-1q2d3drtxrzs5/s-h5113n79yl-0bxcqc5.lock +0 -0
  54. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h51113xoox-10de2hp.lock +0 -0
  55. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h5111704w7-0vdq7gq.lock +0 -0
  56. data/ext/itsi_scheduler/Cargo.toml +1 -1
  57. data/ext/itsi_scheduler/src/itsi_scheduler.rs +9 -3
  58. data/ext/itsi_scheduler/src/lib.rs +1 -0
  59. data/ext/itsi_server/Cargo.lock +2956 -0
  60. data/ext/itsi_server/Cargo.toml +73 -29
  61. data/ext/itsi_server/src/default_responses/mod.rs +11 -0
  62. data/ext/itsi_server/src/env.rs +43 -0
  63. data/ext/itsi_server/src/lib.rs +114 -75
  64. data/ext/itsi_server/src/prelude.rs +2 -0
  65. data/ext/itsi_server/src/{body_proxy → ruby_types/itsi_body_proxy}/big_bytes.rs +10 -5
  66. data/ext/itsi_server/src/{body_proxy/itsi_body_proxy.rs → ruby_types/itsi_body_proxy/mod.rs} +29 -8
  67. data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +344 -0
  68. data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +264 -0
  69. data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +362 -0
  70. data/ext/itsi_server/src/{response/itsi_response.rs → ruby_types/itsi_http_response.rs} +84 -40
  71. data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +233 -0
  72. data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +565 -0
  73. data/ext/itsi_server/src/ruby_types/itsi_server.rs +86 -0
  74. data/ext/itsi_server/src/ruby_types/mod.rs +48 -0
  75. data/ext/itsi_server/src/server/{bind.rs → binds/bind.rs} +59 -24
  76. data/ext/itsi_server/src/server/binds/listener.rs +444 -0
  77. data/ext/itsi_server/src/server/binds/mod.rs +4 -0
  78. data/ext/itsi_server/src/server/{tls → binds/tls}/locked_dir_cache.rs +57 -19
  79. data/ext/itsi_server/src/server/{tls.rs → binds/tls.rs} +120 -31
  80. data/ext/itsi_server/src/server/byte_frame.rs +32 -0
  81. data/ext/itsi_server/src/server/http_message_types.rs +97 -0
  82. data/ext/itsi_server/src/server/io_stream.rs +2 -1
  83. data/ext/itsi_server/src/server/lifecycle_event.rs +3 -0
  84. data/ext/itsi_server/src/server/middleware_stack/middleware.rs +170 -0
  85. data/ext/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +63 -0
  86. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +94 -0
  87. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +94 -0
  88. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +343 -0
  89. data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +151 -0
  90. data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +316 -0
  91. data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +301 -0
  92. data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +193 -0
  93. data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +64 -0
  94. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +192 -0
  95. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +171 -0
  96. data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +198 -0
  97. data/ext/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +82 -0
  98. data/ext/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +209 -0
  99. data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
  100. data/ext/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
  101. data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +116 -0
  102. data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +411 -0
  103. data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +142 -0
  104. data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +55 -0
  105. data/ext/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +54 -0
  106. data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +51 -0
  107. data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +126 -0
  108. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +187 -0
  109. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +55 -0
  110. data/ext/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +173 -0
  111. data/ext/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +31 -0
  112. data/ext/itsi_server/src/server/middleware_stack/mod.rs +381 -0
  113. data/ext/itsi_server/src/server/mod.rs +7 -5
  114. data/ext/itsi_server/src/server/process_worker.rs +65 -14
  115. data/ext/itsi_server/src/server/redirect_type.rs +26 -0
  116. data/ext/itsi_server/src/server/request_job.rs +11 -0
  117. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +150 -50
  118. data/ext/itsi_server/src/server/serve_strategy/mod.rs +9 -6
  119. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +399 -165
  120. data/ext/itsi_server/src/server/signal.rs +33 -26
  121. data/ext/itsi_server/src/server/size_limited_incoming.rs +107 -0
  122. data/ext/itsi_server/src/server/thread_worker.rs +218 -107
  123. data/ext/itsi_server/src/services/cache_store.rs +74 -0
  124. data/ext/itsi_server/src/services/itsi_http_service.rs +257 -0
  125. data/ext/itsi_server/src/services/mime_types.rs +1416 -0
  126. data/ext/itsi_server/src/services/mod.rs +6 -0
  127. data/ext/itsi_server/src/services/password_hasher.rs +83 -0
  128. data/ext/itsi_server/src/services/rate_limiter.rs +580 -0
  129. data/ext/itsi_server/src/services/static_file_server.rs +1340 -0
  130. data/ext/itsi_tracing/Cargo.toml +1 -0
  131. data/ext/itsi_tracing/src/lib.rs +362 -33
  132. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0994n8rpvvt9m/s-h510hfz1f6-1kbycmq.lock +0 -0
  133. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0bob7bf4yq34i/s-h5113125h5-0lh4rag.lock +0 -0
  134. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2fcodulrxbbxo/s-h510h2infk-0hp5kjw.lock +0 -0
  135. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2iak63r1woi1l/s-h510h2in4q-0kxfzw1.lock +0 -0
  136. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2kk4qj9gn5dg2/s-h5113124kv-0enwon2.lock +0 -0
  137. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2mwo0yas7dtw4/s-h510hfz1ha-1udgpei.lock +0 -0
  138. data/itsi-scheduler-100.png +0 -0
  139. data/lib/itsi/scheduler/version.rb +1 -1
  140. data/lib/itsi/scheduler.rb +11 -6
  141. metadata +117 -24
  142. data/CHANGELOG.md +0 -5
  143. data/CODE_OF_CONDUCT.md +0 -132
  144. data/LICENSE.txt +0 -21
  145. data/ext/itsi_error/src/from.rs +0 -71
  146. data/ext/itsi_server/extconf.rb +0 -6
  147. data/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  148. data/ext/itsi_server/src/request/itsi_request.rs +0 -277
  149. data/ext/itsi_server/src/request/mod.rs +0 -1
  150. data/ext/itsi_server/src/response/mod.rs +0 -1
  151. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +0 -13
  152. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -5
  153. data/ext/itsi_server/src/server/itsi_server.rs +0 -244
  154. data/ext/itsi_server/src/server/listener.rs +0 -327
  155. /data/ext/itsi_server/src/server/{bind_protocol.rs → binds/bind_protocol.rs} +0 -0
@@ -1,59 +1,64 @@
1
- use std::sync::{atomic::AtomicI8, LazyLock};
1
+ use std::sync::{
2
+ atomic::{AtomicBool, AtomicI8},
3
+ LazyLock,
4
+ };
2
5
 
3
6
  use nix::libc::{self, sighandler_t};
4
7
  use tokio::sync::{self, broadcast};
5
8
 
6
9
  use super::lifecycle_event::LifecycleEvent;
7
10
 
11
+ pub static SIGINT_COUNT: AtomicI8 = AtomicI8::new(0);
12
+ pub static SHUTDOWN_REQUESTED: AtomicBool = AtomicBool::new(false);
8
13
  pub static SIGNAL_HANDLER_CHANNEL: LazyLock<(
9
14
  broadcast::Sender<LifecycleEvent>,
10
15
  broadcast::Receiver<LifecycleEvent>,
11
16
  )> = LazyLock::new(|| sync::broadcast::channel(5));
12
17
 
13
- pub static SIGINT_COUNT: AtomicI8 = AtomicI8::new(0);
18
+ pub fn send_lifecycle_event(event: LifecycleEvent) {
19
+ SIGNAL_HANDLER_CHANNEL.0.send(event).ok();
20
+ }
21
+
14
22
  fn receive_signal(signum: i32, _: sighandler_t) {
15
23
  SIGINT_COUNT.fetch_add(-1, std::sync::atomic::Ordering::SeqCst);
16
- match signum {
24
+ let event = match signum {
17
25
  libc::SIGTERM | libc::SIGINT => {
26
+ SHUTDOWN_REQUESTED.store(true, std::sync::atomic::Ordering::SeqCst);
18
27
  SIGINT_COUNT.fetch_add(2, std::sync::atomic::Ordering::SeqCst);
19
28
  if SIGINT_COUNT.load(std::sync::atomic::Ordering::SeqCst) < 2 {
20
- SIGNAL_HANDLER_CHANNEL.0.send(LifecycleEvent::Shutdown).ok();
29
+ Some(LifecycleEvent::Shutdown)
21
30
  } else {
22
31
  // Not messing about. Force shutdown.
23
- SIGNAL_HANDLER_CHANNEL
24
- .0
25
- .send(LifecycleEvent::ForceShutdown)
26
- .ok();
32
+ Some(LifecycleEvent::ForceShutdown)
27
33
  }
28
34
  }
29
- libc::SIGUSR1 => {
30
- SIGNAL_HANDLER_CHANNEL.0.send(LifecycleEvent::Restart).ok();
31
- }
32
- libc::SIGTTIN => {
33
- SIGNAL_HANDLER_CHANNEL
34
- .0
35
- .send(LifecycleEvent::IncreaseWorkers)
36
- .ok();
37
- }
38
- libc::SIGTTOU => {
39
- SIGNAL_HANDLER_CHANNEL
40
- .0
41
- .send(LifecycleEvent::DecreaseWorkers)
42
- .ok();
43
- }
44
- _ => {}
35
+ libc::SIGUSR2 => Some(LifecycleEvent::PrintInfo),
36
+ libc::SIGUSR1 => Some(LifecycleEvent::Restart),
37
+ libc::SIGHUP => Some(LifecycleEvent::Reload),
38
+ libc::SIGTTIN => Some(LifecycleEvent::IncreaseWorkers),
39
+ libc::SIGTTOU => Some(LifecycleEvent::DecreaseWorkers),
40
+ libc::SIGCHLD => Some(LifecycleEvent::ChildTerminated),
41
+ _ => None,
42
+ };
43
+
44
+ if let Some(event) = event {
45
+ send_lifecycle_event(event);
45
46
  }
46
47
  }
47
48
 
48
49
  pub fn reset_signal_handlers() -> bool {
49
50
  SIGINT_COUNT.store(0, std::sync::atomic::Ordering::SeqCst);
51
+ SHUTDOWN_REQUESTED.store(false, std::sync::atomic::Ordering::SeqCst);
52
+
50
53
  unsafe {
51
54
  libc::signal(libc::SIGTERM, receive_signal as usize);
52
55
  libc::signal(libc::SIGINT, receive_signal as usize);
53
- libc::signal(libc::SIGUSR1, receive_signal as usize);
54
56
  libc::signal(libc::SIGUSR2, receive_signal as usize);
57
+ libc::signal(libc::SIGUSR1, receive_signal as usize);
58
+ libc::signal(libc::SIGHUP, receive_signal as usize);
55
59
  libc::signal(libc::SIGTTIN, receive_signal as usize);
56
60
  libc::signal(libc::SIGTTOU, receive_signal as usize);
61
+ libc::signal(libc::SIGCHLD, receive_signal as usize);
57
62
  }
58
63
  true
59
64
  }
@@ -62,9 +67,11 @@ pub fn clear_signal_handlers() {
62
67
  unsafe {
63
68
  libc::signal(libc::SIGTERM, libc::SIG_DFL);
64
69
  libc::signal(libc::SIGINT, libc::SIG_DFL);
65
- libc::signal(libc::SIGUSR1, libc::SIG_DFL);
66
70
  libc::signal(libc::SIGUSR2, libc::SIG_DFL);
71
+ libc::signal(libc::SIGUSR1, libc::SIG_DFL);
72
+ libc::signal(libc::SIGHUP, libc::SIG_DFL);
67
73
  libc::signal(libc::SIGTTIN, libc::SIG_DFL);
68
74
  libc::signal(libc::SIGTTOU, libc::SIG_DFL);
75
+ libc::signal(libc::SIGCHLD, libc::SIG_DFL);
69
76
  }
70
77
  }
@@ -0,0 +1,107 @@
1
+ use bytes::Buf;
2
+ use hyper::body::Body;
3
+ use hyper::body::Frame;
4
+ use hyper::body::SizeHint;
5
+ use std::error::Error;
6
+ use std::fmt;
7
+ use std::ops::Deref;
8
+ use std::pin::Pin;
9
+ use std::sync::atomic::AtomicUsize;
10
+ use std::sync::atomic::Ordering;
11
+ use std::task::Context;
12
+ use std::task::Poll;
13
+ use tracing::debug;
14
+
15
+ /// Custom error to indicate that the maximum body size was exceeded.
16
+ #[derive(Debug)]
17
+ pub struct MaxBodySizeReached;
18
+ impl fmt::Display for MaxBodySizeReached {
19
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20
+ write!(f, "Maximum body size reached")
21
+ }
22
+ }
23
+
24
+ impl Error for MaxBodySizeReached {}
25
+
26
+ #[derive(Debug)]
27
+ pub struct SizeLimitedIncoming<B> {
28
+ pub inner: B,
29
+ pub limit: AtomicUsize,
30
+ current: usize,
31
+ }
32
+
33
+ impl<B> Deref for SizeLimitedIncoming<B> {
34
+ type Target = B;
35
+
36
+ fn deref(&self) -> &Self::Target {
37
+ &self.inner
38
+ }
39
+ }
40
+
41
+ impl<B> SizeLimitedIncoming<B> {
42
+ pub fn new(inner: B) -> Self {
43
+ Self {
44
+ inner,
45
+ limit: AtomicUsize::new(usize::MAX),
46
+ current: 0,
47
+ }
48
+ }
49
+ }
50
+
51
+ impl<B> Body for SizeLimitedIncoming<B>
52
+ where
53
+ B: Body + Unpin,
54
+ B::Data: Buf,
55
+ // Ensure that the inner error converts into our boxed error type.
56
+ B::Error: Into<Box<dyn Error + Send + Sync>>,
57
+ {
58
+ type Data = B::Data;
59
+ type Error = Box<dyn Error + Send + Sync>;
60
+
61
+ fn poll_frame(
62
+ mut self: Pin<&mut Self>,
63
+ cx: &mut Context<'_>,
64
+ ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
65
+ // Pin the inner body.
66
+ let inner = Pin::new(&mut self.inner);
67
+ match inner.poll_frame(cx) {
68
+ Poll::Ready(Some(Ok(frame))) => {
69
+ // Use public methods since we cannot match on the private enum.
70
+ if frame.is_data() {
71
+ match frame.into_data() {
72
+ Ok(data) => {
73
+ let len = data.remaining();
74
+ self.current += len;
75
+ debug!(
76
+ target: "option::max_body",
77
+ "current: {}, limit: {}",
78
+ self.current, self.limit.load(Ordering::Relaxed)
79
+ );
80
+ if self.current > self.limit.load(Ordering::Relaxed) {
81
+ Poll::Ready(Some(Err(Box::new(MaxBodySizeReached))))
82
+ } else {
83
+ Poll::Ready(Some(Ok(Frame::data(data))))
84
+ }
85
+ }
86
+ // Should not occur if is_data() was true, but pass through if it does.
87
+ Err(frame) => Poll::Ready(Some(Ok(frame))),
88
+ }
89
+ } else {
90
+ // For non-data frames (e.g. trailers), just pass them along.
91
+ Poll::Ready(Some(Ok(frame)))
92
+ }
93
+ }
94
+ Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e.into()))),
95
+ Poll::Ready(None) => Poll::Ready(None),
96
+ Poll::Pending => Poll::Pending,
97
+ }
98
+ }
99
+
100
+ fn is_end_stream(&self) -> bool {
101
+ self.inner.is_end_stream()
102
+ }
103
+
104
+ fn size_hint(&self) -> SizeHint {
105
+ self.inner.size_hint()
106
+ }
107
+ }