1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
//! This crate provides `incomplete!()`, a compile-time checked version of `unimplemented!()`.
//!
//! Motivation for and discussion around this macro can be found in the
//! [rust-internals](https://internals.rust-lang.org/t/compile-time-checked-version-of-unimplemented/4837)
//! thread, as well as the [RFC issue](https://github.com/rust-lang/rfcs/issues/1911). Some of it
//! is repeated below.
//!
//! We all know and love the `unimplemented!()` macro for keeping track of things we haven't yet
//! gotten around to. However, it is only checked at runtime if a certain code path is encountered.
//! This is fine in many cases, such as for corner-cases you don't expect to have to deal with yet.
//! But when writing new code from scratch (especially when porting), refactoring large amounts of
//! code, or building comprehensive new features, you often have segments of code that you haven't
//! implemented yet, **but you know you'll have to**.
//!
//! The basic motivation for this macro is to introduce a construct to indicate that a piece of
//! code *needs* to be filled in (i.e., the program should not compile while it is present), but
//! that the developer wants to postpone coding up until later.
//!
//! As an example, consider a refactor that requires replacing all `Foo`s and `Bar`s with `Baz`s.
//! Most of the conversions are straightforward, but some require deeper changes (like `Baz`
//! requiring some additional values that aren't readily available in a particular segment of the
//! code). You may want to first finish translating all the `Foo`s and `Bar`s, and only *after*
//! that deal with the corner cases.
//!
//! Normally in this case, the developer might add a `// TODO` comment, or an `unimplemented!()`
//! statement. However, this approach has some drawbacks. In particular, these both still let the
//! code compile when present. Thus, after the "first pass", the developer must *remember* to also
//! grep for all the `unimplemented()`s and `// TODO`s (*and* filter out any that aren't relevant
//! to the refactor in question).
//!
//! The macro implemented by this crate provides a way to tell the compiler "don't let the code
//! compile while this is unimplemented", while still running type checks and the borrow checker so
//! you can fully complete other segments of code in the meantime.
//!
//! Ideally, this macro would have its own compiler lint so that the resulting error directly said
//! something along the lines of "required code segment not completed". However, until RFC issue
//! 1911 sees some progress, this crate hacks around the issue by "abusing" another lint and making
//! it a fatal warning. The result works mostly as desired: it will only error out after all
//! compiler passes complete successfully, and can be evaluated either as a statement or as an
//! expression.
//!
//! # Example
//!
//! ```rust,ignore
//! #[macro_use] extern crate incomplete;
//! fn foo() -> bool {
//! incomplete!()
//! }
//! fn main() {
//! foo();
//! }
//! ```
//!
//! produces
//!
//! ```text
//! error: value assigned to `incomplete` is never read
//! --> src/main.rs:5:5
//! |
//! 5 | incomplete!()
//! | ^^^^^^^^^^^^^
//! |
//! ```
//!
//! # Notes
//!
//! As of the time of writing, the stable compiler will only produce a *warning*, not an *error*,
//! when `incomplete!()` is used. This is because it doesn't correctly interpret the use of
//! compiler directives on statements. On nightly this has been fixed.
//!
//! Also, this macro abuses an existing Rust compiler lint behind the scenes. Since the compiler
//! insists on telling you *where* every lint warning-turned-error originates from, you will
//! unfortunately also get a message along the lines of
//!
//! ```text
//! note: lint level defined here
//! --> src/main.rs:5:13
//! |
//! 5 | let x = incomplete!(bool);
//! | ^^^^^^^^^^^^^^^^^
//! = note: this error originates in a macro outside of the current crate
//! ```
#![deny(missing_docs)]
/// Indicate that a segment of code must be filled out before compilation is allowed to succeed.
///
/// # Examples
///
/// ```rust,ignore
/// #[macro_use] extern crate incomplete;
///
/// fn main() {
/// let x = incomplete!(bool);
/// if x == true {
/// println!("profit");
/// }
/// }
/// ```
///
/// would produce
///
/// ```text
/// error: value assigned to `incomplete` is never read
/// --> src/main.rs:5:13
/// |
/// 5 | let x = incomplete!(bool);
/// | ^^^^^^^^^^^^^^^^^
/// |
/// ```
///
/// You can leave the type argument out if the compiler can already infer the type.
/// ```
#[macro_export]
macro_rules! incomplete {
($ty:ty) => {{
#[allow(unused_variables)]
let mut incomplete = 42;
if false {
#[forbid(unused_assignments)]
{incomplete = 1;}
}
unsafe { ::std::mem::uninitialized::<$ty>() }
}};
() => { incomplete!(_) }
}