Which syntax is better for assertion? assert_that!(v).xx vs v.must_xx.or_fail_with(msg!())

I'm currently building a assertion library.


docs: must - Rust

Gist for syntax comparison: https://gist.github.com/kdy1997/c79ab89585c748429cb244e63f5d2595

Current syntax is

result.must_be_ok_and(|val| {
  val.must_be(5) // returns assertion
}.or(fail!("lazy {}", "eval"));
// .or is optional and used to know source of panic.

// with customization (lazy evaluation is for this)
let parser: fn(&str) -> Result<Lit, ParseError> = parse_lit;
parser.must_parse("false").as_ok(Lit::Bool(false)); // .or(fail!()) is optional

// below is available with current design, but not implemented in example

Current design

  • Evaluated on drop or or(fail!()) (only once, or takes self)
  • Chaining assertion is not supported (available, but need some work)
  • Extends types directly based on trait it implements.
  • or(fail!()) is used to provide location of panic

And I'm considering changing it to assert_that!(). So before doing that, I want to hear some opinions about syntax, and know if it's available to make assert_that! optional. Then syntax would be

assert_that!(Some(5)).must_be_some_and(|val| {
}).with_msg("lazy evaluation");
Some(5).must_be_some_and(|val| {

// with customization
let parser: fn(&str) -> Result<Lit, ParseError> = parse_lit;
  .with_remainder(""); // rustfmt

Because function name like with_msg can be used by user code, it cannot be added to other types.

and I'm considering changing name of fast-fail methods as an alternative option.


.take_or_fail_with(msg!()) //
let parser: fn(&str) -> Result<Lit, ParseError> = parse_lit;

then syntax would be

  .or_fail_with(msg!("")); // location of or_fail_with can be captured

What do you think about this ideas?
And which syntax do you prefer?
I mean, or_fail_with(msg!()) vs assert_that!().with_msg()

Edit: formatted source code

Edit: changed number to header as reddit render all of them as '1.'

Edit: added a link to gist

Edit: removed completely irrelevant stuffs (I can't understand why I wrote that here..)

Are you aware how py.test provides assertions (How to write and report assertions in tests — pytest documentation)?

TLDR is that you write just assert [1, 2, 3] == [1, 8, 3], and the library itself figures out that you are comparing lists and that the second element differs, so it is able to provide a nice error message. In my experience, this is hugely more convenient that hamcrest/assertj style of matches. I wonder if something like this is possible in Rust. There is no run time introspection, but there is a rich type system and macros...