/*******************************************************************************
 *
 *    Copyright (c) 2025 - 2026 Haixing Hu.
 *
 *    SPDX-License-Identifier: Apache-2.0
 *
 *    Licensed under the Apache License, Version 2.0.
 *
 ******************************************************************************/
//! # SupplierOnce Types
//!
//! Provides one-time supplier implementations that generate and
//! return values without taking any input parameters, consuming
//! themselves in the process.
//!
//! # Overview
//!
//! A **SupplierOnce** is a functional abstraction similar to
//! `Supplier`, but can only be called once. The `get()` method
//! consumes `self`, ensuring the supplier cannot be reused.
//!
//! # Key Characteristics
//!
//! - **Single use**: Can only call `get()` once
//! - **Consumes self**: The method takes ownership of `self`
//! - **Holds `FnOnce`**: Can capture and move non-cloneable values
//! - **Type-system guaranteed**: Prevents multiple calls at compile
//!   time
//!
//! # Use Cases
//!
//! 1. **Lazy initialization**: Delay expensive computation until
//!    needed
//! 2. **One-time resource consumption**: Generate value by consuming
//!    a resource
//! 3. **Move-only closures**: Hold closures that capture moved
//!    values
//!
//! # Examples
//!
//! ## Lazy Initialization
//!
//! ```rust
//! use qubit_function::{BoxSupplierOnce, SupplierOnce};
//!
//! let once = BoxSupplierOnce::new(|| {
//!     println!("Expensive initialization");
//!     42
//! });
//!
//! let value = once.get(); // Only initializes once
//! assert_eq!(value, 42);
//! ```
//!
//! ## Moving Captured Values
//!
//! ```rust
//! use qubit_function::{BoxSupplierOnce, SupplierOnce};
//!
//! let resource = String::from("data");
//! let once = BoxSupplierOnce::new(move || resource);
//!
//! let value = once.get();
//! assert_eq!(value, "data");
//! ```
//!
use crate::macros::{
    impl_box_once_conversions,
    impl_closure_once_trait,
};
use crate::predicates::predicate::Predicate;
use crate::suppliers::macros::{
    impl_box_supplier_methods,
    impl_supplier_common_methods,
    impl_supplier_debug_display,
};
use crate::transformers::transformer::Transformer;

mod box_supplier_once;
pub use box_supplier_once::BoxSupplierOnce;

// ==========================================================================
// SupplierOnce Trait
// ==========================================================================

/// One-time supplier trait: generates a value consuming self.
///
/// Similar to `Supplier`, but can only be called once. The `get()`
/// method consumes `self`, ensuring the supplier cannot be reused.
///
/// # Key Characteristics
///
/// - **Single use**: Can only call `get()` once
/// - **Consumes self**: The method takes ownership of `self`
/// - **Holds `FnOnce`**: Can capture and move non-cloneable values
/// - **Type-system guaranteed**: Prevents multiple calls at compile
///   time
///
/// # Use Cases
///
/// 1. **Lazy initialization**: Delay expensive computation until
///    needed
/// 2. **One-time resource consumption**: Generate value by consuming
///    a resource
/// 3. **Move-only closures**: Hold closures that capture moved
///    values
///
/// # Examples
///
/// ## Lazy Initialization
///
/// ```rust
/// use qubit_function::{BoxSupplierOnce, SupplierOnce};
///
/// let once = BoxSupplierOnce::new(|| {
///     println!("Expensive computation");
///     42
/// });
///
/// let value = once.get(); // Prints: Expensive computation
/// assert_eq!(value, 42);
/// // once is now consumed and cannot be used again
/// ```
///
/// ## Resource Consumption
///
/// ```rust
/// use qubit_function::{BoxSupplierOnce, SupplierOnce};
///
/// let resource = String::from("data");
/// let once = BoxSupplierOnce::new(move || {
///     resource // Move the resource
/// });
///
/// let value = once.get();
/// assert_eq!(value, "data");
/// ```
///
pub trait SupplierOnce<T> {
    /// Generates and returns the value, consuming self.
    ///
    /// This method can only be called once because it consumes
    /// `self`. This ensures type-system level guarantee that the
    /// supplier won't be called multiple times.
    ///
    /// # Returns
    ///
    /// The generated value of type `T`
    ///
    /// # Examples
    ///
    /// ```rust
    /// use qubit_function::{BoxSupplierOnce, SupplierOnce};
    ///
    /// let once = BoxSupplierOnce::new(|| 42);
    /// assert_eq!(once.get(), 42);
    /// // once is consumed here
    /// ```
    fn get(self) -> T;

    /// Converts to `BoxSupplierOnce`.
    ///
    /// # Returns
    ///
    /// A new `BoxSupplierOnce<T>` instance
    ///
    /// # Examples
    ///
    /// ```rust
    /// use qubit_function::SupplierOnce;
    ///
    /// let closure = || 42;
    /// let boxed = closure.into_box();
    /// assert_eq!(boxed.get(), 42);
    /// ```
    fn into_box(self) -> BoxSupplierOnce<T>
    where
        Self: Sized + 'static,
    {
        BoxSupplierOnce::new(move || self.get())
    }

    /// Converts the supplier to a `Box<dyn FnOnce() -> T>`.
    ///
    /// This method consumes the current supplier and wraps it in a `Box` as a
    /// trait object, allowing it to be used where a dynamically dispatched
    /// `FnOnce` is needed.
    ///
    /// # Returns
    ///
    /// A `Box<dyn FnOnce() -> T>` that executes the supplier when called.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use qubit_function::SupplierOnce;
    ///
    /// let closure = || 42;
    /// let fn_once = closure.into_fn();
    /// assert_eq!(fn_once(), 42);
    /// ```
    fn into_fn(self) -> impl FnOnce() -> T
    where
        Self: Sized + 'static,
    {
        move || self.get()
    }

    /// Converts the supplier to a `BoxSupplierOnce`.
    ///
    /// This is a convenience method that clones the current supplier and
    /// wraps it in a `BoxSupplierOnce`. This is useful for type erasure and
    /// creating homogenous collections of suppliers.
    ///
    /// # Returns
    ///
    /// A new `BoxSupplierOnce<T>` instance.
    ///
    /// # Note
    ///
    /// This requires the `SupplierOnce` to be `Clone` because it only
    /// borrows `&self` but must create a new owned `BoxSupplierOnce`. The
    /// clone provides the owned value needed for the new instance.
    fn to_box(&self) -> BoxSupplierOnce<T>
    where
        Self: Clone + Sized + 'static,
    {
        self.clone().into_box()
    }

    /// Converts the supplier to a `Box<dyn FnOnce() -> T>`.
    ///
    /// This method clones the current supplier and wraps it in a `Box` as a
    /// trait object, allowing it to be used where a dynamically dispatched
    /// `FnOnce` is needed.
    ///
    /// # Returns
    ///
    /// A `Box<dyn FnOnce() -> T>` that executes the supplier when called.
    ///
    /// # Note
    ///
    /// This requires the `SupplierOnce` to be `Clone` since `to_fn` only
    /// borrows `&self` but needs to produce a `FnOnce` which will be
    /// consumed. The underlying supplier is cloned to provide an owned value
    /// that the returned closure can consume.
    fn to_fn(&self) -> impl FnOnce() -> T
    where
        Self: Clone + Sized + 'static,
    {
        self.clone().into_fn()
    }
}
