We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Errors Are Values step 14 of 24
Define a structured validation error
Implement a name validator with a structured error type. Callers should be able to inspect which rule failed and display a useful message.
pub enum ValidationError {
Empty,
TooLong { len: usize, max: usize },
BadChar { ch: char, index: usize },
}
pub fn validate(name: String, max: usize) -> Result<String, ValidationError>
Keep the variant and field names shown above, derive Debug, implement
std::fmt::Display, and implement std::error::Error by hand.
Validate in this order
- If
nameis empty, returnEmpty, even whenmaxis zero. - Count the Unicode scalar values with
name.chars().count(). If the count exceedsmax, returnTooLong { len, max }. - Find the first character for which
ch.is_alphanumeric()is false andch != '_'. ReturnBadCharwith that character and its zero-based position inname.chars(). - Otherwise return the original name unchanged.
Do not trim, lowercase or normalize the input. A whitespace-only name is not empty: it fails the length rule or character rule. The length rule takes precedence even if an invalid character occurs at the start.
Here, a character means a Unicode scalar value, not a byte or a user-perceived
character. "héllo" contains five scalar values and six UTF-8 bytes. A visually
similar decomposed spelling can have a different count and validation result.
Use the specified Unicode-aware predicate rather than an ASCII-only check.
Exact error output
The harness checks the Display message and derived Debug output:
| Error | Display | Debug |
|---|---|---|
Empty |
name must not be empty |
Empty |
TooLong { len: 11, max: 5 } |
name is 11 characters, maximum is 5 |
TooLong { len: 11, max: 5 } |
BadChar { ch: '-', index: 2 } |
invalid character '-' at index 2 |
BadChar { ch: '-', index: 2 } |
Substitute the actual values in each message. Keep the wording characters
even when the length is one. For BadChar, put the character's Display form
between literal single quotes, as in write!(f, "invalid character '{ch}' at index {index}").
Do not add escaping to that message. Derived Debug supplies its own character
escaping separately.
| Name | Maximum | Result |
|---|---|---|
"ada" |
10 |
Ok("ada") |
"a_b9" |
4 |
Ok("a_b9") |
"日本語" |
3 |
Ok("日本語") |
"-" |
0 |
TooLong { len: 1, max: 0 } |
"é-" |
2 |
BadChar { ch: '-', index: 1 } |
These are validation failures with no underlying cause. Leave source() at
its default None; the harness checks that there is no source. Successful
results contain the original string, including its original spelling.
Implement the formatting trait
The starter derives Debug but does not implement Display. Its empty Error
implementation therefore fails with E0277: Error requires both supertraits.
Add impl fmt::Display for ValidationError. Its method has this signature:
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
Match the three variants and return each arm's write!(f, ...) result.
This passes any formatting failure back to the caller. The trait signature
above is a fragment to put inside the implementation, not a standalone program.
Once Display is implemented, .to_string() is available through the standard
blanket implementation of ToString. The existing empty Error implementation
needs no methods for this type. Lowercase messages without trailing punctuation
follow the standard library's error-message convention and this task's contract.
What Error adds
Error provides a common interface for reporting errors and inspecting optional
causes. Implementing it does not automatically convert your type into every
other error type: ? still needs a suitable conversion into the enclosing
function's error type. Standard conversions do support boxing compatible error
types into Box<dyn Error>.
Send, Sync and 'static are useful bounds for many error APIs, but they are
not supertraits of Error. This enum satisfies them because it contains only
usize and char fields. A borrowed or thread-local error type can still
implement Error while being unsuitable for APIs requiring those extra bounds.
See the Error trait documentation and character predicate. This exercise requires compilation, passing tests and Clippy with warnings denied. Its Debug fixtures reflect the supported compiler; Debug text is not a stable interchange format across toolchain changes.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.