Repository: tokio-rs/tokio
File: tokio/src/sync/semaphore.rs (Rust)

Code before:
///
///         // refills the permits each 1/rate seconds.
///         let jh = tokio::spawn({
///             let sem = sem.clone();
///
///             async move {
///                 let time_slice = 1.0 / (rate as f32);
///
///                 loop {
///                     sleep(Duration::from_secs_f32(time_slice)).await;
///
///                     let cap = rate - sem.available_permits();
///                     sem.add_permits(std::cmp::min(cap, 1));
///                 }
///             }
///         });
///
///         Self { jh, sem }
///     }
///
///     async fn acquire(&self) -> Result<SemaphorePermit<'_>, AcquireError> {
///         self.sem.acquire().await
///     }
///
///     async fn close(self) {
///         self.jh.abort();
///         let _ = self.jh.await;
///
///         self.sem.close();
///     }
/// }
///
/// #[tokio::main]
/// async fn main() {
///     let bucket = TokenBucket::new(1);
///
///     for _ in 0..5 {
///         bucket
///             .acquire()
///             .await
///             .map(|permit| permit.forget())
///             .unwrap();
///
///         // do the operation
///     }
///
///     bucket.close().await;
/// }
/// ```
///
/// [`PollSemaphore`]: https://docs.rs/tokio-util/latest/tokio_util/sync/struct.PollSemaphore.html

Review comment (bug):
I would probably forget the permit here. Otherwise, the user might use this incorrectly and not forget the permit.

Code after:
///                     }
///                 }
///             }
///         });
///
///         Self { jh, sem }
///     }
///
///     async fn acquire(&self) -> Result<(), AcquireError> {
///         self.sem.acquire().await.map(|p| p.forget())
///     }
///
///     async fn close(self) {
///         self.sem.close();
///         self.jh.abort();
///         let _ = self.jh.await;
///     }
/// }
///
/// #[tokio::main]
/// async fn main() {
///     let capacity = 5; // operation per second
///     let update_interval = Duration::from_secs_f32(1.0 / capacity as f32);
///     let bucket = TokenBucket::new(update_interval, capacity);
///
///     for _ in 0..5 {
///         bucket.acquire().await.unwrap();
///
///         // do the operation
///     }
///
///     bucket.close().await;
/// }
/// ```
///
/// Limit the number of incoming requests being handled at the same time.
///
/// Similar to limiting the number of simultaneously opened files, network handles
/// are a limited resource. Allowing an unbounded amount of requests to be processed
/// could result in a denial-of-service, among many other issues.
///
/// This example uses an `Arc<Semaphore>` instead of a global variable.
/// To limit the number of requests that can be processed at the time,
/// we acquire a permit for each task before spawning it. Once acquired,
/// a new task is spawned; and once finished, the permit is dropped inside
/// of the task to allow others to spawn. Permits must be acquired via
/// [`Semaphore::acquire_owned`] to be movable across the task boundary.
/// (Since our semaphore is not a global variable — if it was, then `acquire` would be enough.)
///
/// ```no_run
/// use std::sync::Arc;