#![deny(rustdoc::broken_intra_doc_links)]

use duplicate::duplicate_item;
use num::Complex;

//-------------------------------------------------------------
/// Compound negation and assignment.
pub trait NegAssign {
    /// Performs the negation.
    fn neg_assign(&mut self);
}

#[duplicate_item(
    T;
    [f64];
    [Complex<f64>];
)]
/// Compound negation and assignment.
impl NegAssign for T {
    /// Performs the negation of `self`.
    fn neg_assign(&mut self) {
        *self = -*self;
    }
}

//-------------------------------------------------------------

//-------------------------------------------------------------
#[cfg(test)]
mod tests {
    use super::*;
    use num::Complex;

    mod native64 {
        use super::*;

        #[test]
        fn test_neg_assign_f64() {
            let mut value = 1.0_f64;
            value.neg_assign();
            let expected_value = -1.0_f64;
            assert_eq!(value, expected_value);

            let mut value = -2.0_f64;
            value.neg_assign();
            let expected_value = 2.0_f64;
            assert_eq!(value, expected_value);
        }

        #[test]
        fn test_neg_assign_complex_f64() {
            let mut value = Complex::new(1.0, -2.0);
            value.neg_assign();
            let expected_value = Complex::new(-1.0, 2.0);
            assert_eq!(value, expected_value);

            let mut value = Complex::new(-3.0, 4.0);
            value.neg_assign();
            let expected_value = Complex::new(3.0, -4.0);
            assert_eq!(value, expected_value);
        }
    }

    #[cfg(feature = "rug")]
    mod rug53 {
        use super::*;
        use crate::kernels::rug::{ComplexRugStrictFinite, RealRugStrictFinite};
        use rug::Float;
        use try_create::New;

        const PRECISION: u32 = 53;

        #[test]
        fn test_neg_assign_real_rug() {
            let mut value = RealRugStrictFinite::<PRECISION>::new(Float::with_val(PRECISION, 1.0));
            value.neg_assign();
            let expected_value =
                RealRugStrictFinite::<PRECISION>::new(Float::with_val(PRECISION, -1.0));
            assert_eq!(value, expected_value);

            let mut value = RealRugStrictFinite::<PRECISION>::new(Float::with_val(PRECISION, -2.0));
            value.neg_assign();
            let expected_value =
                RealRugStrictFinite::<PRECISION>::new(Float::with_val(PRECISION, 2.0));
            assert_eq!(value, expected_value);
        }

        #[test]
        fn test_neg_assign_complex_rug() {
            let mut value = ComplexRugStrictFinite::<PRECISION>::new(rug::Complex::with_val(
                PRECISION,
                (
                    Float::with_val(PRECISION, 1.0),
                    Float::with_val(PRECISION, -2.0),
                ),
            ));
            value.neg_assign();
            let expected_value = ComplexRugStrictFinite::<PRECISION>::new(rug::Complex::with_val(
                PRECISION,
                (
                    Float::with_val(PRECISION, -1.0),
                    Float::with_val(PRECISION, 2.0),
                ),
            ));
            assert_eq!(value, expected_value);

            let mut value = ComplexRugStrictFinite::<PRECISION>::new(rug::Complex::with_val(
                PRECISION,
                (
                    Float::with_val(PRECISION, -3.0),
                    Float::with_val(PRECISION, 4.0),
                ),
            ));
            value.neg_assign();
            let expected_value = ComplexRugStrictFinite::<PRECISION>::new(rug::Complex::with_val(
                PRECISION,
                (
                    Float::with_val(PRECISION, 3.0),
                    Float::with_val(PRECISION, -4.0),
                ),
            ));
            assert_eq!(value, expected_value);
        }
    }
}
//-------------------------------------------------------------
