boolean-validation
Level: warn · Article: Errors
Your type signatures are lying to you.
What it checks
A function named validate_*, verify_* or is_valid* that returns
bool. Plain predicates (is_empty, check_flag) are not validation and
are left alone. Validation has a reason to say no, and false cannot carry
it.
Don’t
#![allow(unused)]
fn main() {
fn validate_email(s: &str) -> bool {
s.contains('@') && !s.starts_with('@')
}
fn register(input: &str) -> Result<(), ApiError> {
if !validate_email(input) {
return Err(ApiError::Invalid("email")); // which rule? the user has to guess
}
Ok(())
}
}
Do
#![allow(unused)]
fn main() {
enum EmailError {
MissingAt,
MissingLocalPart,
}
struct Email(String);
impl Email {
fn parse(s: &str) -> Result<Self, EmailError> {
if !s.contains('@') {
return Err(EmailError::MissingAt);
}
if s.starts_with('@') {
return Err(EmailError::MissingLocalPart);
}
Ok(Email(s.to_lowercase()))
}
}
}
The reason travels with the failure, and the success is a type: nothing past this line checks the email again.
Silence it
#![allow(unused)]
fn main() {
// rabot: allow(boolean-validation) a pure predicate used in a filter; there is no caller to inform
fn is_valid_utf8(bytes: &[u8]) -> bool { .. }
}