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!(_) } }