wip 0.1.1

Crate providing traits and macros to use while developing Rust code
Documentation
#![warn(missing_docs)]
#![warn(rustdoc::broken_intra_doc_links)]

//! # wip -- The crate you'll never put into production
//!
//! `wip` helps you during Rust development by helping signal when something
//! is unfinished.
//!
//! It plays a role similar to the [`std::todo`] macro, but emits warning on use,
//! so that a proper CI blocks uses of this crate from reaching production.
//!
//! ![Screenshot of the helix editor displaying various warnings emitted by this crate](https://codeberg.org/dureuill/wip/raw/branch/main/assets/example.png)
//!
//! # What's inside?
//!
//! - `wip` extension methods for [`Result`] and [`Option`] via [`WipResultExt::wip`] and [`WipOptionExt::wip`].
//!   They function like `unwrap` but emit warnings on use, so that you remember to remove them before merging that PR!
//! - `clone_fixme` extension method for any clonable object, for clones that you might later regret, via [`WipCloneExt::clone_fixme`].
//! - `wip!()` macros that emit warnings ([`wip!`]) and work with iterators ([`wip_iter!`]) and futures ([`wip_future!`], you guessed it)
//! - A `fixme()` macro that doesn't panic like [`wip!`], but still emit a warning, to keep track of all these `// FIXME: handle edge case` in your code...
//!
//! # How to use?
//!
//! 1. Add the crate to your dependencies.
//! 2. (optional)
//!    glob import the prelude in your files: `use wip::prelude::*;`
//!    with the one from this crate.
//! 3. Profit!
//!
//! This crate relies on deprecation warnings, so make sure you don't `#![allow(deprecated)]`,
//! lest it won't warn you as intended.
//!
//! # Alternatives
//!
//! I don't currently know of crates exposing the same functionality.
//! However, if you don't like the idea of adding a dependency for this,
//! did you know you could use doc comments over expressions to benefit from a free warning?
//!
//! ```norust
//! unused doc comment
//! use `//` for a plain comment
//! `#[warn(unused_doc_comments)]` on by default
//! ```
//!
//! # No genAI
//!
//! This crate does not use any genAI tooling and intends on staying so.

use std::fmt::Debug;

/// Extension trait for [`std::result::Result`] to expose the [`WipResultExt::wip`] method.
pub trait WipResultExt<T> {
    /// Similar to [`std::result::Result::expect`], but intentionally deprecated to emit a visible warning,
    /// and explicit on the intention.
    ///
    /// Use to defer handling errors during development.
    #[deprecated = "explicitly handle the error case or replace with an unwrap/expect if you can prove it cannot happen"]
    fn wip(self) -> T;
}

/// Extension trait for [`std::option::Option`] to expose the [`WipOptionExt::wip`] method.
pub trait WipOptionExt<T> {
    /// Similar to [`std::option::Option::expect`], but intentionally deprecated to emit a visible warning,
    /// and explicit on the intention.
    ///
    /// Use to defer handling errors during development.
    #[deprecated = "explicitly handle the `None` case or replace with an unwrap/expect if you can prove it cannot happen"]
    fn wip(self) -> T;
}

/// Extension trait for any clonable `T` to expose the [`WipCloneExt::clone_fixme`] method.
pub trait WipCloneExt: Clone {
    /// Similar to [`Clone::clone`], but intentionally deprecated to emit a visible warning,
    /// and explicit on the dev intention to remove it later.
    ///
    /// Use to defer performance handling during development.
    #[deprecated = "rewrite code to make this clone unnecessary or replace with a clone if you really need it"]
    fn clone_fixme(&self) -> Self;
    /// Similar to [`Clone::clone_from`], but intentionally deprecated to emit a visible warning,
    /// and explicit on the dev intention to remove it later.
    ///
    /// Use to defer performance handling during development.
    #[deprecated = "rewrite code to make this clone unnecessary or replace with a clone if you really need it"]
    fn clone_from_fixme(&mut self, source: &Self) {
        Self::clone_from(self, source);
    }
}

impl<T> WipCloneExt for T
where
    T: Clone,
{
    fn clone_fixme(&self) -> Self {
        Self::clone(self)
    }
}

impl<T, E: Debug> WipResultExt<T> for Result<T, E> {
    fn wip(self) -> T {
        self.expect("unfinished development")
    }
}

impl<T> WipOptionExt<T> for Option<T> {
    fn wip(self) -> T {
        self.expect("unfinished development")
    }
}

/// Indicates unfinished code, emits a deprecation warning, and **panics** if reached.
///
/// This can be useful if you are prototyping and just want a placeholder to let your code pass type analysis.
///
/// Similar to [`std::todo`], but emits a warning on use.
#[macro_export]
macro_rules! wip {
    () => {{
        #[deprecated = "implement missing functionality or this will panic at runtime"]
        fn wip() -> ! {
            std::todo!()
        }
        wip()
    }};
     ($($arg:tt)+) => {{
            #[deprecated = "implement missing functionality or this will panic at runtime"]
            fn wip() -> ! {
                std::todo!($($arg)+)
            }
            wip()
     }};
}

/// Indicates unfinished code, emits a deprecation warning, but **does not** panic if reached.
///
/// This macro is useful as a quick note that something must be fixed before hitting production,
/// but no panic is necessary.
///
/// ```
/// wip::fixme!("handle edge case where i == j");
/// ```
#[macro_export]
macro_rules! fixme {
    ($reason:literal) => {{
        #[deprecated = $reason]
        fn fixme() {}
        fixme();
    }};
}

/// Indicates unfinished code, emits a deprecation warning, **panics** if reached, works for `impl Iterator`.
///
/// Regular [`wip`] does not work for iterators, because `!` does not implement `Iterator`.
///
/// # Examples
///
/// Use when Rust cannot infer the concrete type of an iterator you didn't write yet:
///
/// ```
/// fn my_unfinished_iterator() -> impl Iterator<Item=usize> {
///     wip::wip_iter!()
/// }
/// ```
///
/// Otherwise, you can use the regular [`wip`].
///
/// ## Another branch specifies the type
/// ```
/// fn my_unfinished_iterator() -> impl Iterator<Item=usize> {
///     if true {
///         [0, 1, 2].iter().map(|x| x*2)
///     } else {
///         wip::wip!()
///     }
/// }
/// ```
///
/// ## Specific return type expected
///
/// ```
/// fn my_unfinished_iterator() -> std::iter::Once<usize> {
///     wip::wip!()
/// }
/// ```
#[macro_export]
macro_rules! wip_iter {
    () => {{
        #[deprecated = "implement missing functionality or this will panic at runtime"]
        fn wip<T>() -> std::iter::Empty<T> {
            std::todo!()
        }
        wip()
    }};
    ($($arg:tt)+) => {{
        #[deprecated = "implement missing functionality or this will panic at runtime"]
        fn wip<T>() -> std::iter::Empty<T> {
            std::todo!($($arg)+)
        }
        wip()
    }};
}

/// Indicates unfinished code, emits a deprecation warning, **panics** if reached, works for `impl Future`.
///
/// Regular [`wip`] does not work for futures, because `!` does not implement `Future`.
///
/// # Examples
///
/// Use when Rust cannot infer the concrete type of a future you didn't write yet:
///
/// ```
/// fn my_unfinished_future() -> impl Future<Output=usize> {
///     wip::wip_future!()
/// }
/// ```
///
/// Otherwise, you can use the regular [`wip`].
///
/// ## Another branch specifies the type
/// ```
/// fn my_unfinished_future() -> impl Future<Output=usize> {
///     if true {
///         std::future::ready(42)
///     } else {
///         wip::wip!()
///     }
/// }
/// ```
///
/// ## Specific return type expected
///
/// ```
/// fn my_unfinished_future() -> std::future::Ready<usize> {
///     wip::wip!()
/// }
/// ```
#[macro_export]
macro_rules! wip_future {
    () => {{
        #[deprecated = "implement missing functionality or this will panic at runtime"]
        fn wip<T>() -> std::future::Ready<T> {
            std::todo!()
        }
        wip()
    }};
    ($($arg:tt)+) => {{
        #[deprecated = "implement missing functionality or this will panic at runtime"]
        fn wip<T>() -> std::future::Ready<T> {
            std::todo!($($arg)+)
        }
        wip()
    }};
}

/// Prelude to glob import for easy use of the provided functions and extension traits.
///
/// # Example
///
/// ```
/// use wip::prelude::*;
///
/// fn test() {
///     None.wip()
/// }
/// ```
pub mod prelude {
    pub use crate::{
        WipCloneExt as _, WipOptionExt as _, WipResultExt as _, fixme, wip, wip_future, wip_iter,
    };
}