pub struct Yoshi { /* private fields */ }Expand description
The main Yoshi error type with enterprise-grade performance optimization.
Yoshi is a highly structured and extensible error type designed for
complex applications. It combines a categorized error kind, contextual
information, and optional backtrace capture into a single, cohesive unit.
§Fields
kind: The primary classification of the error, provided byYoshiKind.backtrace: An optionalYoshiBacktraceproviding stack trace information (only withstdfeature).contexts: A vector ofYoContextinstances, providing additional details and context about the error’s propagation.instance_id: A unique identifier for eachYoshierror instance.created_at: TheSystemTimewhen the error was created (only withstdfeature).
§Examples
Basic error creation:
use yoshi_std::{Yoshi, YoshiKind};
let err = Yoshi::new(YoshiKind::Internal {
message: "Something went wrong internally".into(),
source: None,
component: None,
});
println!("Error: {}", err);Creating an error with context:
use yoshi_std::{Yoshi, YoshiKind, HatchExt};
fn load_data() -> Result<(), Yoshi> {
// Simulate a file not found error
let io_error = io::Error::new(ErrorKind::NotFound, "data.json not found");
let error = Yoshi::from(io_error)
.context("Failed to load user preferences".to_string())
.with_metadata("user_id", "test_user")
.with_suggestion("Ensure data.json is in the correct directory.");
Err(error)
}
match load_data() {
Ok(_) => println!("Data loaded successfully"),
Err(error) => eprintln!("Error: {}", error),
}Implementations§
Source§impl Yoshi
impl Yoshi
Sourcepub fn new(kind: YoshiKind) -> Self
pub fn new(kind: YoshiKind) -> Self
Creates a new Yoshi error with optimized allocation and monitoring.
This is the primary constructor for Yoshi errors. It increments
a global instance counter and, if the std feature is enabled and
backtraces are enabled via environment variables (RUST_BACKTRACE
or RUST_LIB_BACKTRACE), it captures a backtrace.
§Arguments
kind- TheYoshiKindthat categorizes this error.
§Returns
A new Yoshi error instance.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
let err = Yoshi::new(YoshiKind::NotFound {
resource_type: "User".into(),
identifier: "john.doe".into(),
search_locations: None,
});
assert!(matches!(err.kind(), YoshiKind::NotFound { .. }));Sourcepub fn foreign<E>(e: E) -> Self
pub fn foreign<E>(e: E) -> Self
Creates a new Yoshi error by wrapping a foreign Error trait object.
This is an explicit conversion for generic error types, allowing them
to be integrated into the Yoshi error chain without requiring a
blanket From implementation that might conflict or cause issues
with unstable features.
The type name of the wrapped error is captured for diagnostic purposes.
§Type Parameters
E- The type of the foreign error, which must implementError,Send,Sync, and have a'staticlifetime.
§Arguments
e- The foreign error instance to wrap.
§Returns
A new Yoshi error with its kind to YoshiKind::Foreign.
§Examples
use std::io;
use yoshi_std::{Yoshi, YoshiKind};
#[derive(Debug)]
struct CustomError;
impl std::fmt::Display for CustomError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "a custom error occurred")
}
}
impl std::error::Error for CustomError {}
let io_error = io::Error::new(io::ErrorKind::Other, "disk full");
let yoshi_io_error = Yoshi::foreign(io_error);
assert!(matches!(yoshi_io_error.kind(), YoshiKind::Foreign { .. }));
println!("Wrapped IO error: {}", yoshi_io_error);
let custom_error = CustomError;
let yoshi_custom_error = Yoshi::foreign(custom_error);
assert!(matches!(yoshi_custom_error.kind(), YoshiKind::Foreign { .. }));
println!("Wrapped custom error: {}", yoshi_custom_error);Sourcepub const fn instance_id(&self) -> u32
pub const fn instance_id(&self) -> u32
Gets the unique instance ID for debugging and correlation.
Each Yoshi error instance is assigned a unique u64 ID upon creation.
This ID can be used to track specific error occurrences in logs or
telemetry systems, especially in highly concurrent environments.
§Returns
The unique instance ID of this Yoshi error.
§Examples
let err1 = Yoshi::new(YoshiKind::Internal {
message: "test".into(),
source: None,
component: None,
});
let err2 = Yoshi::new(YoshiKind::Internal {
message: "test".into(),
source: None,
component: None,
});
assert_ne!(err1.instance_id(), err2.instance_id());
println!("Error 1 ID: {}", err1.instance_id());
println!("Error 2 ID: {}", err2.instance_id());Sourcepub const fn kind(&self) -> &YoshiKind
pub const fn kind(&self) -> &YoshiKind
Returns a reference to the YoshiKind of this error.
This allows inspecting the high-level classification of the error and accessing its specific fields.
§Returns
A constant reference to the YoshiKind enum variant.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
let err = Yoshi::new(YoshiKind::NotFound {
resource_type: "User".into(),
identifier: "john.doe".into(),
search_locations: None,
});
match err.kind() {
YoshiKind::NotFound { identifier, .. } => {
println!("User not found: {}", identifier);
}
_ => (),
}Sourcepub const fn severity(&self) -> u8
pub const fn severity(&self) -> u8
Gets the error severity level (0-100).
This is a convenience method that delegates to self.kind().severity().
§Returns
A u8 value indicating the severity of the error.
§Examples
let internal_error = YoshiKind::Internal {
message: "simulated error".into(),
source: None,
component: None,
};
assert_eq!(internal_error.severity(), 80);
let validation_error = YoshiKind::Validation {
field: "email".into(),
message: "Invalid format".into(),
expected: None,
actual: None,
};
assert_eq!(validation_error.severity(), 20);Sourcepub const fn is_transient(&self) -> bool
pub const fn is_transient(&self) -> bool
Checks if this is a transient error that might succeed on retry.
This is a convenience method that delegates to self.kind().is_transient().
§Returns
true if the error’s kind is considered transient, false otherwise.
§Examples
let timeout_error = YoshiKind::Timeout {
operation: "API call".into(),
duration: Duration::from_secs(10),
expected_max: None,
};
assert!(timeout_error.is_transient());
let config_error = YoshiKind::Config {
message: "Missing key".into(),
source: None,
config_path: None,
};
assert!(!config_error.is_transient());Sourcepub fn context(self, msg: impl Into<String>) -> Self
pub fn context(self, msg: impl Into<String>) -> Self
Adds a context message to the error.
This method enhances the error with additional diagnostic information, making it easier to trace the origin and propagation of failures.
§Arguments
msg- The context message. It can be any type that converts into aString.
§Returns
The modified Yoshi error instance with the new context.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
let err = Yoshi::new(YoshiKind::Internal {
message: "database query failed".into(),
source: None,
component: None,
})
.context("Attempting to fetch user data");
println!("Error: {}", err);§Panics
This method may panic if context storage fails, though this is extremely unlikely.
Sourcepub fn with_suggestion(self, s: impl Into<String>) -> Self
pub fn with_suggestion(self, s: impl Into<String>) -> Self
Adds a suggestion to the error’s primary context.
This method adds a human-readable suggestion to the current Yoshi error.
The suggestion is stored in the primary (most recent) context associated
with this error.
§Arguments
s- The suggestion message. It can be any type that converts into aString.
§Returns
The modified Yoshi error instance with the new suggestion.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
/// let err = Yoshi::new(YoshiKind::Io(std::io::Error::new(std::io::ErrorKind::PermissionDenied, "file access denied")))
.with_suggestion("Check file permissions or path.");
assert!(err.suggestion().as_deref() == Some("Check file permissions or path."));§Panics
This method may panic if the context storage fails, though this is extremely unlikely.
Sourcepub fn with_component(self, component: impl Into<String>) -> Self
pub fn with_component(self, component: impl Into<String>) -> Self
Attaches a component identifier to the error’s primary context.
This method adds a component identifier to help categorize and trace errors within different parts of a system or application. The component information is stored as metadata with the key “component”.
§Arguments
component- The component identifier. It can be any type that converts into aString.
§Returns
The modified Yoshi error instance with the component information.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
let err = Yoshi::new(YoshiKind::Internal {
message: "operation failed".into(),
source: None,
component: None,
})
.with_component("database");
// Component can be retrieved from metadata
let ctx = err.primary_context().unwrap();
assert_eq!(ctx.metadata.get("component").map(|s| s.as_ref()), Some("database"));§Panics
This method may panic if the context storage fails, though this is extremely unlikely.
Sourcepub fn with_shell(self, shell: impl Any + Send + Sync + 'static) -> Self
pub fn with_shell(self, shell: impl Any + Send + Sync + 'static) -> Self
Attaches a typed shell to the error’s primary context.
This method allows embedding arbitrary Rust types within the error’s context.
This is useful for passing structured, type-safe debugging information
that can be retrieved later using shell::<T>().
§Arguments
shell- The data to attach. It must implementAny,Send,Sync, and have a'staticlifetime.
§Returns
The modified Yoshi error instance with the new shell.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
#[derive(Debug, PartialEq)]
struct RequestContext {
user_id: u64,
request_path: String,
}
let err = Yoshi::new(YoshiKind::Internal {
message: "handler failed".into(),
source: None,
component: None,
})
.with_shell(RequestContext { user_id: 123, request_path: "/api/data".to_string() });
let ctx_payload = err.shell::<RequestContext>().unwrap();
assert_eq!(ctx_payload.user_id, 123);§Panics
This method may panic if the shell storage fails, though this is extremely unlikely.
Sourcepub fn with_priority(self, priority: u8) -> Self
pub fn with_priority(self, priority: u8) -> Self
Sets the priority for the error’s primary context.
Priority can be used to indicate the relative importance of a context message, influencing how errors are logged or processed by error handling systems. Higher values indicate higher priority.
§Arguments
priority- The priority level (0-255).
§Returns
The modified Yoshi error instance with the updated priority.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
let err = Yoshi::new(YoshiKind::Internal {
message: "critical failure".into(),
source: None,
component: None,
})
.with_priority(250); // Highest priority
assert_eq!(err.primary_context().unwrap().priority, 250);§Panics
This method ensures that there is at least one context before updating priority. If no contexts exist, it creates one automatically, so this method should not panic.
Sourcepub fn with_metadata(self, k: impl Into<String>, v: impl Into<String>) -> Self
pub fn with_metadata(self, k: impl Into<String>, v: impl Into<String>) -> Self
Adds metadata to the error’s primary context.
Metadata are key-value pairs that provide additional, unstructured diagnostic information. These can be used for logging, filtering, or passing arbitrary data alongside the error.
§Arguments
k- The metadata key. It can be any type that converts into aString.v- The metadata value. It can be any type that converts into aString.
§Returns
The modified Yoshi error instance with the new metadata.
§Examples
use yoshi_std::{Yoshi, YoshiKind, Arc};
let err = Yoshi::new(YoshiKind::Internal {
message: "cache read failed".into(),
source: None,
component: None,
})
.with_metadata("cache_key", "user_profile_123")
.with_metadata("region", "us-east-1");
let metadata = &err.primary_context().unwrap().metadata;
assert_eq!(metadata.get(&Arc::from("cache_key")).map(|s| s.as_ref()), Some("user_profile_123"));
assert_eq!(metadata.get(&Arc::from("region")).map(|s| s.as_ref()), Some("us-east-1"));§Panics
This method may panic if metadata storage fails, though this is extremely unlikely.
Sourcepub fn with_location(self, location: YoshiLocation) -> Self
pub fn with_location(self, location: YoshiLocation) -> Self
Sets location information on the error’s primary context.
This method attaches source code location information to the error’s primary context,
helping with debugging and error tracing. It consumes self and returns a modified Self.
§Arguments
location- TheYoshiLocationto set.
§Returns
The modified Yoshi error instance with the location set.
§Examples
use yoshi_std::{Yoshi, YoshiKind, YoshiLocation};
let location = YoshiLocation::new("src/main.rs", 10, 5);
let err = Yoshi::new(YoshiKind::Internal {
message: "operation failed".into(),
source: None,
component: None,
})
.with_location(location);
assert_eq!(err.primary_context().unwrap().location.unwrap().file, "src/main.rs");
assert_eq!(err.primary_context().unwrap().location.unwrap().line, 10);§Panics
This method may panic if location storage fails, though this is extremely unlikely.
Sourcepub const fn backtrace(&self) -> Option<&YoshiBacktrace>
pub const fn backtrace(&self) -> Option<&YoshiBacktrace>
Returns a reference to the optional backtrace.
The backtrace is only available when the std feature is enabled and
RUST_BACKTRACE or RUST_LIB_BACKTRACE environment variables are set.
§Returns
An Option containing a reference to the YoshiBacktrace if available,
otherwise None.
§Examples
let err = Yoshi::new(YoshiKind::Internal {
message: "test error".into(),
source: None,
component: None,
});
if let Some(bt) = err.backtrace() {
println!("Backtrace: {}", bt);
}Sourcepub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T>
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T>
Returns a reference to the underlying foreign error (if YoshiKind::Foreign).
This method allows downcasting the boxed dyn Error contained within a
YoshiKind::Foreign variant to a concrete type.
§Type Parameters
T- The concrete type to downcast to, which must implementError.
§Returns
An Option containing a reference to the downcasted error of type T,
or None if the error is not YoshiKind::Foreign or cannot be downcasted
to the specified type.
/// # Examples
use std::io;
use yoshi_std::{Yoshi, YoshiKind};
let io_err = io::Error::new(io::ErrorKind::NotFound, "file.txt not found");
let yoshi_err = Yoshi::foreign(io_err);
// Attempt to downcast to io::Error
if let Some(err) = yoshi_err.downcast_ref::<io::Error>() {
assert_eq!(err.kind(), io::ErrorKind::NotFound);
} else {
panic!("Expected io::Error");
}Sourcepub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T>
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T>
Returns a mutable reference to the underlying foreign error (if YoshiKind::Foreign).
This method allows mutable downcasting the boxed dyn Error contained within a
YoshiKind::Foreign variant to a concrete type.
§Type Parameters
T- The concrete type to downcast to, which must implementError.
§Returns
/// An Option containing a mutable reference to the downcasted error of type T,
or None if the error is not YoshiKind::Foreign or cannot be downcasted
to the specified type.
Sourcepub fn primary_context(&self) -> Option<&YoContext>
pub fn primary_context(&self) -> Option<&YoContext>
Returns the primary context associated with this error.
The primary context is typically the most recent or most relevant context added to the error, often containing the most specific information about the direct cause of the failure.
§Returns
An Option containing a reference to the primary YoContext,
or None if no contexts have been added.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
let err = Yoshi::new(YoshiKind::Internal {
message: "failed step".into(),
source: None,
component: None,
})
.context("Step 1 failed")
.context("Step 2 failed"); // This is the primary context
assert_eq!(err.primary_context().unwrap().message.as_deref(), Some("Step 2 failed"));Sourcepub fn contexts(&self) -> impl Iterator<Item = &YoContext>
pub fn contexts(&self) -> impl Iterator<Item = &YoContext>
Returns an iterator over all contexts associated with this error.
Contexts are ordered from oldest (first added) to newest (most recent, primary).
§Returns
An iterator yielding references to YoContext instances.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
let err = Yoshi::new(YoshiKind::Internal {
message: "original error".into(),
source: None,
component: None,
})
.context("context 1")
.context("context 2");
let messages: Vec<_> = err.contexts().filter_map(|c| c.message.as_deref()).collect();
assert_eq!(messages, vec!["context 1", "context 2"]);Sourcepub fn suggestion(&self) -> Option<&str>
pub fn suggestion(&self) -> Option<&str>
Returns the suggestion from the primary context, if any.
This is a convenience method to quickly access the most relevant suggestion for resolving the error.
§Returns
An Option containing a reference to the suggestion string, or None.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
let err = Yoshi::new(YoshiKind::Io(std::io::Error::new(std::io::ErrorKind::PermissionDenied, "file access denied")))
.with_suggestion("Check file permissions.");
assert_eq!(err.suggestion().as_deref(), Some("Check file permissions."));Sourcepub fn shell<T: 'static>(&self) -> Option<&T>
pub fn shell<T: 'static>(&self) -> Option<&T>
Returns a typed shell from the primary context, if any.
This is a convenience method to quickly access a structured shell from the most relevant context.
§Type Parameters
T- The type of shell to retrieve.
§Returns
An Option containing a reference to the shell of type T, or None.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
#[derive(Debug, PartialEq)]
struct CustomPayload(u32);
let err = Yoshi::new(YoshiKind::Internal {
message: "test".into(),
source: None,
component: None,
})
.with_shell(CustomPayload(123));
/// assert_eq!(err.shell::<CustomPayload>().unwrap().0, 123);Sourcepub fn nest(&self) -> Option<&(dyn Error + 'static)>
pub fn nest(&self) -> Option<&(dyn Error + 'static)>
The nested error, equivalent to source(), but more thematically expressive.
This method provides thematic access to the underlying error source while
maintaining full backwards compatibility with the standard Error trait.
§Returns
An Option containing a reference to the nested error, or None if
there is no underlying source.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
let inner = Yoshi::new(YoshiKind::Internal {
message: "inner failure".into(),
source: None,
component: None,
});
let outer = Yoshi::new(YoshiKind::Internal {
message: "outer failure".into(),
source: Some(Box::new(inner)),
component: None,
});
assert!(outer.nest().is_some());Sourcepub fn laytext(&self) -> Option<&str>
pub fn laytext(&self) -> Option<&str>
The explanation or context attached to the error.
This method provides direct access to the primary context message, offering a thematic alternative to accessing context information.
§Returns
An Option containing a reference to the laytext string, or None
if no context message is available.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
let err = Yoshi::new(YoshiKind::Internal {
message: "base error".into(),
source: None,
component: None,
})
.context("operation failed");
assert_eq!(err.laytext().unwrap(), "operation failed");Sourcepub fn lay(self, msg: impl Into<String>) -> Self
pub fn lay(self, msg: impl Into<String>) -> Self
Adds contextual information using the thematic .lay() method.
This method is equivalent to .context() but provides thematic naming
consistent with the Hatch ecosystem’s metaphorical framework.
§Arguments
msg- The context message to attach.
§Returns
The modified Yoshi error instance with the new context.
§Examples
use yoshi_std::{Yoshi, YoshiKind};
let err = Yoshi::new(YoshiKind::Internal {
message: "base error".into(),
source: None,
component: None,
})
.lay("while processing request");
assert!(err.to_string().contains("while processing request"));Sourcepub fn analyze_contexts(&self) -> ContextAnalysis
pub fn analyze_contexts(&self) -> ContextAnalysis
Gathers analysis results about the contexts in this error.
This method performs a quick scan of all attached contexts to provide aggregated statistics, useful for logging, analytics, or deciding on error handling strategies.
§Returns
A ContextAnalysis struct containing various metrics about the contexts.
§Examples
use yoshi_std::{Yoshi, YoshiKind, YoshiLocation};
let err = Yoshi::new(YoshiKind::Internal {
message: "base error".into(),
source: None,
component: None,
})
.context("Intermediate step")
.with_metadata("key", "value")
.with_suggestion("Try again")
.context("Final step failed")
.with_location(YoshiLocation::new("src/main.rs", 10, 5));
let analysis = err.analyze_contexts();
assert_eq!(analysis.total_contexts, 2);
assert_eq!(analysis.context_depth, 2);
assert!(analysis.has_suggestions);
assert!(analysis.has_location_info);
assert_eq!(analysis.metadata_entries, 1);Trait Implementations§
Source§impl Clone for Yoshi
impl Clone for Yoshi
Source§fn clone(&self) -> Self
fn clone(&self) -> Self
Creates a clone of the Yoshi error.
Note: In std mode, the backtrace is not cloned (as std::backtrace::Backtrace
doesn’t implement Clone). Instead, the clone will have no backtrace (None).
In no_std mode, the backtrace is properly cloned as it only contains basic
location information.
A new unique instance ID is generated for the clone to maintain error tracking.
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Display for Yoshi
impl Display for Yoshi
Source§fn fmt(&self, f: &mut Formatter<'_>) -> Result
fn fmt(&self, f: &mut Formatter<'_>) -> Result
Formats the Yoshi error for display with optimized O(n) error chain traversal.
This implementation provides a comprehensive, human-readable representation of the error, designed for debugging and logging. It uses an optimized iterative approach to traverse error chains, eliminating the O(n²) performance bottleneck present in recursive formatting. The formatter collects the entire error chain first, then renders all information in a single linear pass.
§Performance Characteristics
- Time Complexity: O(n) where n is the total depth of the error chain
- Space Complexity: O(n) for temporary chain storage
- Memory Allocation: Minimized through
OptimizedFormatBufferusage - Scaling: Linear performance even for deep error chains (100+ levels)
§Arguments
f- The formatter to write into.
§Returns
A fmt::Result indicating success or failure of the formatting.
§Examples
let error = Yoshi::new(YoshiKind::Internal {
message: "Operation failed".into(),
source: None,
component: None,
})
.context("While processing request");
println!("{}", error); // Efficient O(n) formattingSource§impl Error for Yoshi
impl Error for Yoshi
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the underlying source of this error.
This method provides access to the root cause of the error chain, enabling compatibility with Rust’s standard error handling mechanisms.
§Returns
An Option containing a reference to the dyn Error source,
or None if there is no underlying cause.