//! Provider of [`UpgetExt`].

use crate::prelude::*;

/// Extention trait for methods with update and get combination.
pub trait UpgetExt<T> {
    /// Update self with given closure and get the result.
    ///
    /// # Examples
    ///
    /// ```
    /// use subject::prelude::*;
    /// use subject::exts::UpgetExt;
    ///
    /// let arr = [1, 3, 4, 2, 5];
    /// let sorted = S(arr).upget(|x| x.sort());
    /// assert_eq!(sorted, [1, 2, 3, 4, 5]);
    /// ```
    fn upget<F>(self, f: F) -> T
    where
        Self: Sized,
        F: FnOnce(&mut T);

    /// Update self with given closure if flag is `true` and get the result.
    ///
    /// # Examples
    ///
    /// ```
    /// use subject::prelude::*;
    /// use subject::exts::UpgetExt;
    ///
    /// let arr = [1, 3, 4, 2, 5];
    /// let ident = S(arr.clone()).upget_if(false, |x| x.sort());
    /// let sorted = S(arr.clone()).upget_if(true, |x| x.sort());
    /// assert_eq!(ident, [1, 3, 4, 2, 5]);
    /// assert_eq!(sorted, [1, 2, 3, 4, 5]);
    /// ```
    fn upget_if<F>(self, flag: bool, f: F) -> T
    where
        Self: Sized,
        F: FnOnce(&mut T);
}

impl<T> UpgetExt<T> for S<T> {
    #[inline]
    fn upget<F>(mut self, f: F) -> T
    where
        Self: Sized,
        F: FnOnce(&mut T),
    {
        f(&mut self.0);
        self.0
    }

    #[inline]
    fn upget_if<F>(self, flag: bool, f: F) -> T
    where
        Self: Sized,
        F: FnOnce(&mut T),
    {
        if flag { self.upget(f) } else { self.0 }
    }
}
