We have two macros that are hidden because they are code de-duplication
tools. However the output they produce is, and has to be, stable so that
we can use them in `units` and `primitives` without inadvertently
breaking semver in `primitives`.
55470f7357 Change `create` to `construct` in rustdocs (Jamil Lambert, PhD)
Pull request description:
In preparation for units 1.0 address #3868 and make sure "constructs" is used instead of "creates" in rustdocs.
ACKs for top commit:
apoelstra:
ACK 55470f73571ce0e0279f5697a252695e8c8df9b5; successfully ran local tests; sure
tcharding:
ACK 55470f7357
Tree-SHA512: 48f9b6cedfca782e698eec4520885f35834582ed098a65b00ccdfa54167c91fe62405f90c9c1e72a671e72ac349af74ac12808ce9e0708799f43d86749590649
7ca5c5ccae Fix rustdoc title on hex_u128_* (Tobin C. Harding)
f1e2564821 Improve docs on parse::int_from_string (Tobin C. Harding)
d97cbc6d27 units: Correct docs on private Sealed trait (Tobin C. Harding)
Pull request description:
Audit the `units::parse` module checking for sanity of the API. Could still possibly do with more improvements to the docs but for the `1.0-alpha` this is good to go IMO.
Close: #3710
ACKs for top commit:
apoelstra:
ACK 7ca5c5ccae1efe5862f21bfc670257837a202517; successfully ran local tests; looks good!
Tree-SHA512: 937e8f6e1ae0a17217b770daffe1968ec9046c86728a360f1297d7027318511fece31440f462fdaeb94c2a69901a970e20bd2599a6d963bfbdf06b25378fe543
I only just worked on this function a week ago and already I couldn't
see from reading the code why it exists. Add a paragraph to the rustdocs
to save the next guy the trouble of working it out.
Phew! dyn compatibility is a non-trivial concept. There are four public
traits in `units`, only one is dyn compatible.
This patch is done in order to check off C-OBJECT from the Rust API
guidelines checklist.
Add a test to check the public traits in `units` for dyn compatibility.
While we are at it add a code comment on `Integer` stating why its not
dyn-compatible.
ref: https://rust-lang.github.io/api-guidelines/flexibility.html#c-object
Change the lint to `warn` in `units/Cargo.toml`.
Allow `missing_errors_doc` in `amount/serde.rs` and `fee_rate/serde.rs`.
Add missing `# Errors` sections to rustdocs where the lint gives a
warning.
Currently `InputString` is in the public API of `units` because of the
trait bound on `parse::int()`. We can just do the monomorphisisation
manually to remove it.
This patch renames `int` to have three different names, one for `&str`
one for `String`, and one for `Box<str>`.
We do not want to commit to any public macros in `units`. Recently we (I
at least) learned that adding `doc(hidden)` signals to users that the
macro is unstable and should not be relied upon.
Hide the remaining two macros so we can release 1.0 and not worry about
later breaking them.
With this applied there are no exported macros that are not hidden.
Verify using `git grep -A 1 macro_export`.
286bf900b1 Address mutants in units (Shing Him Ng)
Pull request description:
Preemptively addressing these mutants before introducing the `cargo-mutants` workflow. There are several types of changes:
- Changes that address mutants that were actually missing
- Changes that address test values that cause `cargo-mutants` to think mutants were missed. For example, `cargo-mutants` will replace the return values for unsigned integer types with 0 and 1. While this case might be tested, the test might be testing this with a call that results in 0 or 1. When `cargo-mutants` substitutes the function call with `Ok(1)`, the test will still pass, and it will consider this a mutant. `cargo-mutants` also replaces operations (+, -, /, %), bitwise operations (&, |, ^, etc), so an operation such as `3 - 2` results in a mutant because changing it to `3 / 2` yields the same result
- TODOs to ignore functions/impls in the future
I uased the following `mutants.toml` config file when running `cargo mutants` and skipped the `Debug`, `Arbitrary`, `Display`, and `Error` impls and the `kani` test:
```
additional_cargo_args = ["--all-features"]
examine_globs = ["units/src/**/*.rs"]
exclude_globs = ["units/src/amount/verification.rs"]
exclude_re = ["impl Debug", "impl Arbitrary", "impl Display", ".*Error", "<impl Visitor for VisitOptAmt<X>>"]
```
I wasn't sure the code for Displaying things needed to be tested with `cargo mutants`, but I'm less sure about the errors so i can kill those mutants too if needed
ACKs for top commit:
tcharding:
ACK 286bf900b1
apoelstra:
ACK 286bf900b1c100d2f5d0a0d45f31a5bf5a0a26ce; successfully ran local tests
Tree-SHA512: 3db9598a5ad92f2013d43876221ce9363cc019cbf720a206768b517a812c8355b7f00594212eb0526c0feb2dc578f88e1df12548f72a2b2360c4d4227de749f7
Preemptively addressing these mutants before introducing the
cargo-mutants workflow
There are several types of changes:
- Changes that address mutants that were actually missing
- Changes that address test values that cause `cargo-mutants` to think
mutants were missed. For example, `cargo-mutants` will replace the
return values for unsigned integer types with 0 and 1. While a function
might be tested, the test might be testing the function with a call that
results in 0 or 1. When `cargo-mutants` substitutes the function call
with `Ok(1)`, the test will still pass, and it will consider this a
mutant. `cargo-mutants` also replaces operations (+, -, /, %), bitwise
operations (&, |, ^, etc), so an operation such as `3 - 2` results in a
mutant because changing it to `3 / 2` yields the same result
- TODOs to ignore functions/impls in the future
0d8e9ef096 Remove usage of impl_from_infallible in leaf crates (Tobin C. Harding)
Pull request description:
Rust macros, while at times useful, are a maintenance nightmare. And we have been bitten by calling macros from other crates multiple times in the past.
In a push to just use less macros remove the usage of the `impl_from_infallible` macro in all the leaf crates and just write the code.
ACKs for top commit:
apoelstra:
ACK 0d8e9ef096fd60fcdb7928697c8f554bf428b754; successfully ran local tests; this is a great change
Tree-SHA512: c4cff4517f7846d91142f26d451c2bcafc014a0921d11ac1487eab087449f12023c3b4fc57e1bc72ed3ea58406b4c3d24bbd846df21353f5d7ecb4a4b8bfb0b2
Rust macros, while at times useful, are a maintenance nightmare. And
we have been bitten by calling macros from other crates multiple times
in the past.
In a push to just use less macros remove the usage of the
`impl_from_infallible` macro in all the leaf crates and just write the
code.
We have a public macro `impl_parse_str` and a helper macro used by it,
both pubicly exported.
As we did for `impl_parse_str_from_int_infallible`; to assist readers
understanding what is going on put the helper below the other.
Done as a separate patch to make the diff easier to read.
Internal change only, no logic change.
This macro is a helper for `impl_parse_str_from_int_infallible` used to
reduce code duplication. It does not, and should not, need to be part of
the public API - hide it.
We have a public macro `impl_parse_str_from_int_infallible` and a helper
macro used by it, both pubicly exported.
To assist readers understanding what is going on put the helper below
the other.
Code move only, no logic change.
Add all the pedantic lints to the repository by way of the repository
manifest. Then enable these lints in the `units` manifest.
Some things worth mentioning:
- Fix `needless_pass_by_value` by adding derives to `FormatOptions`.
- Fix lint `cast_lossless` using `cargo clippy --fix``
- While fixing `lint enum_glob_use` introduce a new style to the
codebase; import enums using a single character. Doing so prevents
namespace clashes, improves clarity, and maintains terseness.
Audit:
Use the following lints locally and audit all the warnings, they produce
many false positives so we can't enable them permentently.
- `cast_possible_truncation`
- `cast_possible_lint`
- `cast_sign_loss`
4cccbfdf76 units: Seal the Integer trait (Tobin C. Harding)
Pull request description:
This trait is an internal thing, users should never implement it.
ACKs for top commit:
sanket1729:
utACK 4cccbfdf76
apoelstra:
ACK 4cccbfdf7628442cc198f6399846ad4e98938494; successfully ran local tests
Tree-SHA512: f48e8ef96d15135990976c77e933ddc735dda577464548478526e37fff49bf453aaacf966967d98a0d5598588b531199627af8e353f845d4c7781f1e1d8de6db
As we do in `bitcoin` add a module for usage in macros to prevent naming
clashes if a module called `core` exists.
Overly paranoid yes but this is bitcoin after all.
There is a range of different wordings used in the docs of constructor
type functions.
Change all to start with `Constructs a new` or `Constructs an empty`.
In functions that act like constructors there is a mixture of the usage
of `creates` and `constructs`.
Replace all occurrences of `creates` with `constructs` in the first line
of docs of constructor like functions.
In an effort to reduce requirement for `alloc`; remove the `String` and
use `InputString` in the hex prefix related error types.
Tested with:
(Note in test code we have to use `"cafe".to_owned()` before this patch
is applied.)
rust```
#[test]
fn hex_prefix_errors() {
let err = hex_remove_prefix("cafe").unwrap_err();
std::println!("{}", err);
std::println!("{:?}", err);
let err = hex_check_unprefixed("0xcafe").unwrap_err();
std::println!("{}", err);
std::println!("{:?}", err);
}
```
Before:
hex string is missing a prefix (e.g. 0x): cafe
MissingPrefixError { hex: "cafe" }
hex string contains a prefix: 0xcafe
ContainsPrefixError { hex: "0xcafe" }
After:
failed to parse 'cafe' as hex because it is missing the '0x' prefix
MissingPrefixError { hex: InputString("cafe") }
failed to parse '0xcafe' as hex because it contains the '0x' prefix
ContainsPrefixError { hex: InputString("0xcafe") }
Currently the `ParseIntError` contains an owned copy of the input
string, this is causing us to have to use `alloc` everywhere.
We already have a alloc-friendly string replacement type, the
`InputString` - use it.
We have a special type for wrapping integer parsing errors, use it.
To test this I added the following tests:
#[test]
pub fn debug_absolute_error_conversion_height() {
let invalid_height = LOCK_TIME_THRESHOLD + 1;
let _ = Height::from_consensus(invalid_height).unwrap();
}
#[test]
pub fn debug_absolute_error_conversion_time() {
let invalid_time = LOCK_TIME_THRESHOLD - 1;
let _ = Time::from_consensus(invalid_time).unwrap();
}
#[test]
#[cfg(feature = "std")]
pub fn debug_absolute_error_conversion_height_string() {
let invalid_height = std::format!("{:x}", LOCK_TIME_THRESHOLD + 1);
let _ = Height::from_hex(&invalid_height).unwrap();
}
#[test]
#[cfg(feature = "std")]
pub fn debug_absolute_error_conversion_time_string() {
let invalid_time = std::format!("{:x}", LOCK_TIME_THRESHOLD - 1);
let _ = Time::from_hex(&invalid_time).unwrap();
}
#[test]
#[cfg(feature = "std")]
pub fn debug_absolute_error_height_invalid_hex_string() {
let _ = Height::from_hex("somerandomshit").unwrap();
}
#[test]
#[cfg(feature = "std")]
pub fn debug_absolute_error_time_invalid_hex_string() {
let _ = Time::from_hex("somerandomshit").unwrap();
}
Which resulted in the following output
Before:
---- locktime::absolute::tests::debug_absolute_error_conversion_height stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_height' panicked at units/src/locktime/absolute.rs:431:56:
called `Result::unwrap()` on an `Err` value: ConversionError { unit: Blocks, input: 500000001 }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
---- locktime::absolute::tests::debug_absolute_error_conversion_height_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_height_string' panicked at units/src/locktime/absolute.rs:444:51:
called `Result::unwrap()` on an `Err` value: ParseHeightError(Conversion(500000001))
---- locktime::absolute::tests::debug_absolute_error_conversion_time stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_time' panicked at units/src/locktime/absolute.rs:437:52:
called `Result::unwrap()` on an `Err` value: ConversionError { unit: Seconds, input: 499999999 }
---- locktime::absolute::tests::debug_absolute_error_height_invalid_hex_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_height_invalid_hex_string' panicked at units/src/locktime/absolute.rs:457:52:
called `Result::unwrap()` on an `Err` value: ParseHeightError(InvalidInteger { source: ParseIntError { kind: InvalidDigit }, input: "somerandomshit" })
---- locktime::absolute::tests::debug_absolute_error_conversion_time_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_time_string' panicked at units/src/locktime/absolute.rs:451:47:
called `Result::unwrap()` on an `Err` value: ParseTimeError(Conversion(499999999))
---- locktime::absolute::tests::debug_absolute_error_time_invalid_hex_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_time_invalid_hex_string' panicked at units/src/locktime/absolute.rs:464:50:
called `Result::unwrap()` on an `Err` value: ParseTimeError(InvalidInteger { source: ParseIntError { kind: InvalidDigit }, input: "somerandomshit" })
After:
---- locktime::absolute::tests::debug_absolute_error_conversion_height stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_height' panicked at units/src/locktime/absolute.rs:432:56:
called `Result::unwrap()` on an `Err` value: ConversionError { unit: Blocks, input: 500000001 }
---- locktime::absolute::tests::debug_absolute_error_conversion_height_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_height_string' panicked at units/src/locktime/absolute.rs:445:51:
called `Result::unwrap()` on an `Err` value: ParseHeightError(Conversion(500000001))
---- locktime::absolute::tests::debug_absolute_error_conversion_time stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_time' panicked at units/src/locktime/absolute.rs:438:52:
called `Result::unwrap()` on an `Err` value: ConversionError { unit: Seconds, input: 499999999 }
---- locktime::absolute::tests::debug_absolute_error_conversion_time_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_time_string' panicked at units/src/locktime/absolute.rs:452:47:
called `Result::unwrap()` on an `Err` value: ParseTimeError(Conversion(499999999))
---- locktime::absolute::tests::debug_absolute_error_height_invalid_hex_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_height_invalid_hex_string' panicked at units/src/locktime/absolute.rs:458:52:
called `Result::unwrap()` on an `Err` value: ParseHeightError(ParseInt(ParseIntError { input: "somerandomshit", bits: 32, is_signed: false, source: ParseIntError { kind: InvalidDigit } }))
---- locktime::absolute::tests::debug_absolute_error_time_invalid_hex_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_time_invalid_hex_string' panicked at units/src/locktime/absolute.rs:465:50:
called `Result::unwrap()` on an `Err` value: ParseTimeError(ParseInt(ParseIntError { input: "somerandomshit", bits: 32, is_signed: false, source: ParseIntError { kind: InvalidDigit } }))
Add to `units::parse` the complete suit of hex unit parsing functions:
- remove prefix
- assert without prefix
- parse with or without prefix
- parse with prefix
- parse without prefix
- parse prefix unchecked
Refactor `bitcoin` to use the exact function we need, removing code
duplication.
This is a breaking change to `units`, it does however keep the current
re-exports from the public, now empty, `bitcoin::error` module.
Move the `strip_hex_prefix` helper function to below where it is called.
Note that I was the original author of this helper so there is no excuse
for it being above - bad Tobin no biscuit.
When creating the ParseIntError in `hex_u32` I (Tobin) just cargo cult
programmed the generic stuff without thinking.
- The `is_signed` field is used to denote whether we were attempting to
parse a signed or unsigned integer, it should be `false`.
- The `bits` field should be directly set to 32.
Move the following unit types to the new `units` crate:
- `locktime::absolute::{Height, Time}`
- `locktime::relative::{Height, Time}`
- `FeeRate`
- `Weight`
Also move the `parse` module as well as constants as required.
Do minimal changes to get things building:
- Feature gate on "alloc" as needed.
- Remove rustdocs that use `bitcoin` types.
- Re-export units types so this is a non-breaking change.
- Fix import paths.