Crates.io | nobug |
lib.rs | nobug |
version | 0.5.0 |
source | src |
created_at | 2024-10-01 13:13:36.378452 |
updated_at | 2024-10-22 19:37:29.847376 |
description | Assertions and active code annotations |
homepage | |
repository | https://git.pipapo.org/cehteh/nobug_rs.git |
max_upload_size | |
id | 1392925 |
size | 61,224 |
NoBug
provides GLARING! assertions and annotations for rust code. These have different
semantic than the stdlib assertions. The Idea behind NoBug
is to have active annotations
with semantic meaning. The annotations are not just comments but actively checked at runtime
or compile time. By using uppercase macros they are easily visible and searchable in source
code.
Unlike the stdlib assertions which panic on failure, the NoBug
assertions will abort the
program and thus are not catchable. Without the unwinding overhead they wont generate any
excess code. Only in debug build tests they will panic because the test harness running tests in
threads and catching panics. When aborting at runtime is not desired then the *_DBG!
variants
of the macros can be used. Those will only check the condition in debug builds. This can be
enforced by disabling the abort_on_fail
feature.
Aside from a generic (and discouraged) [ASSERT!
] macro we provide:
REQUIRE!
] -- checking preconditionsENSURE!
] -- checking postconditionsCHECK!
] -- generic checks for testing and similar cases.std::assert!
macros in tests.Each of those has a correspondending ASSERT_DBG!
, REQUIRE_DBG!
and ENSURE_DBG!
variants that inserts checks only in debug builds.
REQUIRE!
and CHECK!
have somme specializations for const asserts and comparisons which
give more concise error messages.
Since some programs must not abort on assertion failure we provide a abort_on_failure
feature. When this is not enabled then any DIE!
and any other macro calling it will cause a
compile error in release, non-test builds. One can only use the *_DBG!
variants of the nobug
macros then.
Threre is a special [ASSERT_ONCE!
] macro that will only check the condition once and then
never again.
NoBug
defines macros to actively annotate code. Actively means that these macros can do
different things in release or debug builds, depending on configuration:
compile_error!()
]In release builds all annotations are either optimized out or compile errors. Thus they have zero cost in release builds.
We provide following annotation macros (with the noted defaults):
FIXME!
] -- Bug that must be fixed.FIXED!
] -- Annotate fixed bugs.TODO!
] -- Incomplete but required code.DONE!
] -- Completed code.WIP!
] -- Work in progress.IDEA!
] -- Not required improvement of existing code.PLANNED!
] -- Potential future planned feature.FIXME!
, FIXED!
, WIP!
and DONE!
can be augmented with optional code blocks that are
checked at runtime. Notifying about assertions still being valid and detecting regressions.
MOCK!
must have code blocks either a single one or conditional IF-THEN-ELSE blocks. This
can be used where WIP!
is not sufficient.
Nobug logs messages to stderr (using the log or tracing crate is planned for the future). Messages can be of different severity levels.
CRITICAL!
] -- Print a critical message.NOTICE!
] -- Print a notice to the user.TRACE!
] -- Print a trace message to the user.NOTICE_ONCE!
] -- Print a notice to the user.Each of these has a *_DBG!
variant that only logs in debug builds. There is a
[TRACE_DBG_IF!
] macro that does conditional logging in debug builds.
The messages are entries delimited by a colon followed by a space, they always start with the file and line number of the message.
<file>:<line>: <reason>: <message>
where <message>
can have multiple free-form parts each delimited by colon space as well
The above uses some tool macros which may be useful on their own in some cases.
[DIE!
] -- Abort (or panic). compile_error!()
when abort_on_fail
is not enabled.
[ONCE!
] -- Execute a block only once.
[MOCK!
] -- Trivial code mocking.
abort_on_fail
This is enabled by default. When not enabled then [DIE!
] and all macros using it will
cause a compile error in release/non-test builds. This is useful when you want to make
sure that nobug will never abort in release builds. One can only use the *_DBG!
variants
of the nobug macros in release builds then.
const_expr
This is enabled by default. When not enabled then the REQUIRE!
and CHECK!
macros will
not use const {}
expression specializations and fall back to a inferior implementation.
Disabling this feature is required when using a compiler before v1.79.0.
trace_nobug
Makes nobug
TRACE!
all calls to its own macros. This is useful for debugging nobug itself
or to get some quick insight of the a program's progress.
The idea is to use the annotations and assertions to actively document the code. Assertions
ideally stay in the code and are not removed. They are the contract of the code, only when
performance is critical they can be replaced by a the *_DBG!
variant. Keep in mind that in
some cases the compiler can optimize the checks away or do more aggressive optimizations when
it knows that certain conditions are always true.
Nobug assertions are not a substitution for the std::assert!
macros. When required they can
be mixed. For the cases where panics need to be caught and handled the std::assert!
macros
must be used. The NoBug
macros are for the cases where the program is in a undefined state
due to a programming error that can't be detected at compile time and should be aborted.
The annotations can be used to define a stateful workflow, for example:
FIXME!
-> FIXED!
IDEA!
-> WIP!
-> DONE!
PLANNED!
-> TODO!
-> WIP!
-> DONE!
This is not rigid, states can be left out and unused. Only keep whatever makes sense.
Especially the final FIXED!
and DONE!
states can eventually accumulate and clutter the
code. It may still be benefitical to keep them in the code for a while since they guard
against regressions.
Found bugs that are annotated with FIXME!
may as well transformed into a test case within
the unit or integration tests.
Incomplete code can be mocked with MOCK!
and then replaced with the real implementation when
it is done. In some cases this might be preferable to or complement WIP!
since it allows to
run some tests with the mocked code.
Testsuites may prefer to use the CHECK!
macro if appropriate.
In 2006 I started a C Debug library of the same name (https://git.pipapo.org/cehteh/nobug). This implementation will carry some of its ideas over to rust.
Currently we only implemented most basic functionally. In future more features will be added.
#[nobug]
fn example(i: i32 where i > 0) -> i32
where
result < 100
{
...
}