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

Code before:
    /// Sends a new value via the channel, notifying all receivers.
    ///
    /// This method fails if the channel has been closed, which happens when
    /// every receiver has been dropped.
    pub fn send(&self, value: T) -> Result<(), error::SendError<T>> {
        // This is pretty much only useful as a hint anyway, so synchronization isn't critical.
        if 0 == self.receiver_count() {
            return Err(error::SendError(value));
        }

        self.send_modify(|old| *old = value);
        Ok(())
    }

    /// Modifies watched value, notifying all receivers.
    ///
    /// This can useful for modifying the watched value, without
    /// having to allocate a new instance. Additionally, this
    /// method permits sending values even when there are no receivers.
    ///
    /// # Panics
    ///
    /// This function panics if calling `func` results in a panic.
    /// No receivers are notified if panic occurred.
    /// If the panic is caught, this might leave the watched value
    /// in an inconsistent state.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::sync::watch;
    ///
    /// struct State {
    ///     counter: usize,
    /// }
    /// let (state_tx, state_rx) = watch::channel(State { counter: 0 });
    /// state_tx.send_modify(|state| state.counter += 1);
    /// assert_eq!(state_rx.borrow().counter, 1);
    /// ```
    pub fn send_modify<F>(&self, func: F)
    where
        F: FnOnce(&mut T),
    {
        {
            // Acquire the write lock and update the value.
            let mut lock = self.shared.value.write().unwrap();
            // Update the value and catch possible panic inside func.
            let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
                func(&mut lock);
            }));
            // If the func panicked return the panic to the caller.

Review comment (suggestion):
```suggestion
    /// This function panics if calling `func` results in a panic.
    /// No receivers are notified if panic occurred, but if the closure has modified
    /// the value, that change is still visible to future calls to `borrow`.
```

Code after:
    /// Sends a new value via the channel, notifying all receivers.
    ///
    /// This method fails if the channel has been closed, which happens when
    /// every receiver has been dropped.
    pub fn send(&self, value: T) -> Result<(), error::SendError<T>> {
        // This is pretty much only useful as a hint anyway, so synchronization isn't critical.
        if 0 == self.receiver_count() {
            return Err(error::SendError(value));
        }

        self.send_replace(value);
        Ok(())
    }

    /// Modifies watched value, notifying all receivers.
    ///
    /// This can useful for modifying the watched value, without
    /// having to allocate a new instance. Additionally, this
    /// method permits sending values even when there are no receivers.
    ///
    /// # Panics
    ///
    /// This function panics if calling `func` results in a panic.
    /// No receivers are notified if panic occurred, but if the closure has modified
    /// the value, that change is still visible to future calls to `borrow`.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::sync::watch;
    ///
    /// struct State {
    ///     counter: usize,
    /// }
    /// let (state_tx, state_rx) = watch::channel(State { counter: 0 });
    /// state_tx.send_modify(|state| state.counter += 1);
    /// assert_eq!(state_rx.borrow().counter, 1);
    /// ```
    pub fn send_modify<F>(&self, func: F)
    where
        F: FnOnce(&mut T),
    {
        {
            // Acquire the write lock and update the value.
            let mut lock = self.shared.value.write().unwrap();
            // Update the value and catch possible panic inside func.
            let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
                func(&mut lock);
            }));
            // If the func panicked return the panic to the caller.
            if let Err(error) = result {