Crates.io | incomplete |
lib.rs | incomplete |
version | 0.1.3 |
source | src |
created_at | 2017-02-23 19:01:52.393297 |
updated_at | 2018-12-04 18:41:24.370239 |
description | Provides incomplete!(), a compile-time checked version of unimplemented!() |
homepage | https://github.com/jonhoo/incomplete |
repository | https://github.com/jonhoo/incomplete.git |
max_upload_size | |
id | 8655 |
size | 10,750 |
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 thread, as well as the RFC issue. 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.
#[macro_use] extern crate incomplete;
fn foo() -> bool {
incomplete!()
}
fn main() {
foo();
}
produces
error: value assigned to `incomplete` is never read
--> src/main.rs:5:5
|
5 | incomplete!()
| ^^^^^^^^^^^^^
|
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
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