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

Code before:
///
///     assert_eq!(semaphore.available_permits(), 0);
///
///     let permit_attempt = semaphore.try_acquire();
///     assert_eq!(permit_attempt.err(), Some(TryAcquireError::NoPermits));
/// }
/// ```
///
/// Limit number of incoming requests being handled at the same time.
///
/// Similar to limiting the numer of simultaneous opened files, network handles are a limited resource.
/// Allowing an unbounded amount of requests to be processed could result in a denial-of-service,
/// and many other issues.
///
/// However, in contrast to the file example, this example uses a non-static, `Arc`-wrapped `Semaphore`
/// for more fine-grained lifetime and ownership control. The `Arc` allows multiple threads and tasks
/// to share ownership of the semaphore. Here we create a shallow-copy of the `Arc<Semaphore>` reference
/// using `clone`. Then we acquire a permit through the `Arc` from the `Semaphore` via [`Semaphore::acquire_owned`],
/// and move it inside the task. This ensures no non-`'static` variables are referenced from within
/// said task.
///
/// If we leave the scope where the `Arc<Semaphore>` was defined, and references still exist in any
/// of our tasks to it, the `Semaphore` will continue to exist in a static-like context, until all
/// `Arc`s have been dropped.
///
/// ```compile_fail
/// use std::sync::Arc;
/// use tokio::sync::Semaphore;
/// use tokio::net::{TcpListener};
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
///     let semaphore = Arc::new(Semaphore::new(3));
///     let listener = TcpListener::bind("127.0.0.1:8080").await?;
///
///     loop {
///         // Acquire permit before accepting, to avoid needlessly taking up a (finite) file descriptor
///         let permit = semaphore.clone().acquire_owned().await.unwrap();
///         let (mut socket, _) = listener.accept().await?;
///
///         tokio::spawn(async move {
///             // Do work, and drop socket after
///             handle_connection(&mut socket).await;
///             // Explicitly drop the permit, so more tasks can be created
///             drop(permit);
///         });
///     }
/// }
/// ```
///
/// Limit the number of simultaneously opened files in your program.

Review comment (bug):
Right now, the documentation says "This example deliberately fails to compile". Can you fix the compilation failure?

If the problem is the missing `handle_connection`, then you could define it like this:
```
async fn handle_connection(socket: &mut TcpStream) -> Result<()> {
    todo!()
}
```
Or even use # symbols to hide it from the documentation. (You can put  # in front of a line in an example to hide it from the documentation.)

Code after:
///
///     assert_eq!(semaphore.available_permits(), 0);
///
///     let permit_attempt = semaphore.try_acquire();
///     assert_eq!(permit_attempt.err(), Some(TryAcquireError::NoPermits));
/// }
/// ```
///
/// Limit the number of simultaneously opened files in your program.
///
/// Most operating systems have limits on the number of open file
/// handles. Even in systems without explicit limits, resource constraints
/// implicitly set an upper bound on the number of open files. If your
/// program attempts to open a large number of files and exceeds this
/// limit, it will result in an error.
///
/// This example uses a Semaphore with 100 permits. By acquiring a permit from
/// the Semaphore before accessing a file, you ensure that your program opens
/// no more than 100 files at a time. When trying to open the 101st
/// file, the program will wait until a permit becomes available before
/// proceeding to open another file.
/// ```
/// use std::io::Result;
/// use tokio::fs::File;
/// use tokio::sync::Semaphore;
/// use tokio::io::AsyncWriteExt;
///
/// static PERMITS: Semaphore = Semaphore::const_new(100);
///
/// async fn write_to_file(message: &[u8]) -> Result<()> {
///     let _permit = PERMITS.acquire().await.unwrap();
///     let mut buffer = File::create("example.txt").await?;
///     buffer.write_all(message).await?;
///     Ok(()) // Permit goes out of scope here, and is available again for acquisition
/// }
/// ```
///
/// 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.)
///