Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate: add .unwrap()-like functions #42

Closed
wants to merge 1 commit into from
Closed

Validate: add .unwrap()-like functions #42

wants to merge 1 commit into from

Conversation

hinto-janai
Copy link

This adds .unwrap()-like functions:

  • validate_or()
  • validate_or_else()
  • validate_or_default()

Notably, the last one is handy for me in situations where I don't care about errors, I just need a valid struct:

let tmp = read_users_config_file();

// I don't care about what the error was,
// I just want a valid `Config` after this point.
let config = tmp.validate_or_default(&());

/* do stuff with config */

The alternative before this was:

let tmp = read_users_config_file();

let config = match tmp.validate(&()) {
    Ok(_) => tmp,
    Err(_) => Default::default(),
};

/* do stuff with config */

This can get verbose if you're dealing with many validations.


Since none of these functions return errors, it's a waste to collect them, so validate_ok(), a function that early returns a bool on occurring an error instead of allocating+collecting them was implemented, but getting it to work with the derive macro... seemed difficult, so I left it out.

How it would have looked:

if data.validate_ok(&()) {
    println!("data is ok");
}

Current code:

// Looks similar but `validate()` under the
// hood may be allocating a bunch of errors
// to return (that we aren't using...!)
if data.validate(&()).is_ok() {
    println!("data is ok, but at what cost...?");
}

@jprochazk
Copy link
Owner

Hi and thanks for the PR!

Maybe I'm missing something, but can't you do this already with existing Result combinators? (unwrap_or, unwrap_or_else, unwrap_or_default)

let tmp = read_users_config_file();

// the `map` here is to convert `Result<(), Errors>` to `Result<T, Errors>`
let config = tmp.validate(&()).map(|_| tmp).unwrap_or(Default::default());
let config = tmp.validate(&()).map(|_| tmp).unwrap_or_else(|| Default::default());
let config = tmp.validate(&()).map(|_| tmp).unwrap_or_default();

/* do stuff with config */

I don't want to increase the surface area of the library if it's not absolutely necessary.

Since none of these functions return errors, it's a waste to collect them, so validate_ok(), a function that early returns a bool on occurring an error instead of allocating+collecting them was implemented, but getting it to work with the derive macro... seemed difficult, so I left it out.

I have plans to implement this in #1 :)

@hinto-janai
Copy link
Author

Yes, you can already do this, but those chains are quite hard to read compared to:

let config = tmp.validate_or_default(&());

Patterns that appear often tend to receive more concise functions, but,

I don't want to increase the surface area of the library

this is understandable.

@hinto-janai hinto-janai closed this May 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants