neuer-error 0.3.0

Ergonomic error handling for machines and humans.
Documentation
//! Validating data while collecting multiple errors.
#![allow(
	dead_code,
	clippy::missing_docs_in_private_items,
	clippy::print_stderr,
	reason = "Example"
)]

use ::neuer_error::{NeuErr, Result, traits::*};

struct UserData {
	id: u64,
	name: String,
	balance: i64,
}

fn validate_id(id: u64) -> Result<()> {
	if id == 0 { Err(NeuErr::new("ID must be non-zero").into()) } else { Ok(()) }
}

fn validate_name(name: &str) -> Result<()> {
	if name.trim().is_empty() {
		Err(NeuErr::new("Name must not be empty").into())
	} else if !name.chars().all(|c| c.is_alphabetic()) {
		Err(NeuErr::new("Name must only contain alphabetic characters").into())
	} else {
		Ok(())
	}
}

struct User {
	id: u64,
	name: String,
	balance: i64,
}

impl User {
	fn new(data: UserData) -> Result<Self, Vec<NeuErr>> {
		let mut errors = Vec::new();
		let UserData { id, name, balance } = data;

		validate_id(id).or_collect(&mut errors);
		validate_name(&name).or_collect(&mut errors);

		if balance < 0 {
			errors.push(NeuErr::new("Cannot create new user with debt").into());
		}

		if id == 3 {
			errors.push(NeuErr::new(format!("User {id} ({name}) already exists")).into());
		}

		let user = User { id, name, balance };
		if errors.is_empty() { Ok(user) } else { Err(errors) }
	}
}

fn main() {
	match User::new(UserData { id: 3, name: "".to_owned(), balance: -12345 }) {
		Ok(_user) => {
			eprintln!("User valid");
		}
		Err(errors) => {
			for error in errors {
				eprintln!("Error: {error}");
				eprintln!();
			}
		}
	}
}