mod length;
mod valid;
mod value;
pub use self::length::ExpectedLength;
pub use self::valid::ExpectedValid;
pub use self::value::ExpectedValue;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
use crate::display::ErrorDisplay;
use crate::error::{
Backtrace, BacktraceBuilder, Context, Details, RetryRequirement, ToRetryRequirement, Value,
WithContext,
};
use crate::fmt;
use crate::input::{Input, MaybeString};
#[cfg(feature = "full-backtrace")]
type ExpectedBacktrace = crate::error::FullBacktrace;
#[cfg(not(feature = "full-backtrace"))]
type ExpectedBacktrace = crate::error::RootBacktrace;
#[must_use = "error must be handled"]
pub struct Expected<'i, S = ExpectedBacktrace> {
input: MaybeString<'i>,
trace: S,
kind: ExpectedKind<'i>,
}
enum ExpectedKind<'i> {
Value(ExpectedValue<'i>),
Valid(ExpectedValid<'i>),
Length(ExpectedLength<'i>),
}
impl<'i, S> Expected<'i, S>
where
S: Backtrace,
{
pub fn display(&self) -> ErrorDisplay<'_, Self> {
ErrorDisplay::new(self)
}
}
impl<'i, S> Expected<'i, S>
where
S: BacktraceBuilder,
{
#[inline(always)]
fn add_input(&mut self, input: impl Input<'i>) {
if self.input.span().is_within(input.span()) {
self.input = input.into_maybe_string()
}
}
#[inline(always)]
fn add_context(&mut self, context: impl Context) {
self.trace.push(context);
}
fn from_kind(kind: ExpectedKind<'i>) -> Self {
let (input, context) = match &kind {
ExpectedKind::Valid(err) => (err.input(), err.context()),
ExpectedKind::Value(err) => (err.input(), err.context()),
ExpectedKind::Length(err) => (err.input(), err.context()),
};
Self {
kind,
input,
trace: S::from_root(context),
}
}
}
impl<'i, S> Details<'i> for Expected<'i, S>
where
S: Backtrace,
{
fn input(&self) -> MaybeString<'i> {
self.input.clone()
}
fn expected(&self) -> Option<Value<'i>> {
match &self.kind {
ExpectedKind::Value(err) => Some(err.expected()),
ExpectedKind::Valid(_) | ExpectedKind::Length(_) => None,
}
}
fn description(&self, f: &mut dyn fmt::Write) -> fmt::Result {
match &self.kind {
ExpectedKind::Value(err) => fmt::DisplayBase::fmt(err, f),
ExpectedKind::Valid(err) => fmt::DisplayBase::fmt(err, f),
ExpectedKind::Length(err) => fmt::DisplayBase::fmt(err, f),
}
}
fn backtrace(&self) -> &dyn Backtrace {
&self.trace
}
}
impl<'i, S> ToRetryRequirement for Expected<'i, S> {
fn to_retry_requirement(&self) -> Option<RetryRequirement> {
match &self.kind {
ExpectedKind::Value(err) => err.to_retry_requirement(),
ExpectedKind::Valid(err) => err.to_retry_requirement(),
ExpectedKind::Length(err) => err.to_retry_requirement(),
}
}
fn is_fatal(&self) -> bool {
match &self.kind {
ExpectedKind::Value(err) => err.is_fatal(),
ExpectedKind::Valid(err) => err.is_fatal(),
ExpectedKind::Length(err) => err.is_fatal(),
}
}
}
#[cfg(feature = "alloc")]
impl<'i, S> ToRetryRequirement for Box<Expected<'i, S>> {
fn to_retry_requirement(&self) -> Option<RetryRequirement> {
(**self).to_retry_requirement()
}
fn is_fatal(&self) -> bool {
(**self).is_fatal()
}
}
impl<'i, S> WithContext<'i> for Expected<'i, S>
where
S: BacktraceBuilder,
{
const PASSTHROUGH: bool = S::PASSTHROUGH;
fn with_input(mut self, input: impl Input<'i>) -> Self {
self.add_input(input);
self
}
fn with_context(mut self, context: impl Context) -> Self {
self.add_context(context);
self
}
}
#[cfg(feature = "alloc")]
impl<'i, S> WithContext<'i> for Box<Expected<'i, S>>
where
S: BacktraceBuilder,
{
const PASSTHROUGH: bool = S::PASSTHROUGH;
fn with_input(mut self, input: impl Input<'i>) -> Self {
self.add_input(input);
self
}
fn with_context(mut self, context: impl Context) -> Self {
self.add_context(context);
self
}
}
impl<'i, S> fmt::Debug for Expected<'i, S>
where
S: Backtrace,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ErrorDisplay::from_formatter(self, f).banner(true).fmt(f)
}
}
impl<'i, S> fmt::Display for Expected<'i, S>
where
S: Backtrace,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ErrorDisplay::from_formatter(self, f).fmt(f)
}
}
impl<'i, S> From<ExpectedLength<'i>> for Expected<'i, S>
where
S: BacktraceBuilder,
{
fn from(err: ExpectedLength<'i>) -> Self {
Self::from_kind(ExpectedKind::Length(err))
}
}
#[cfg(feature = "alloc")]
impl<'i, S> From<ExpectedLength<'i>> for Box<Expected<'i, S>>
where
S: BacktraceBuilder,
{
fn from(expected: ExpectedLength<'i>) -> Box<Expected<'i, S>> {
Box::new(expected.into())
}
}
impl<'i, S> From<ExpectedValid<'i>> for Expected<'i, S>
where
S: BacktraceBuilder,
{
fn from(err: ExpectedValid<'i>) -> Self {
Self::from_kind(ExpectedKind::Valid(err))
}
}
#[cfg(feature = "alloc")]
impl<'i, S> From<ExpectedValid<'i>> for Box<Expected<'i, S>>
where
S: BacktraceBuilder,
{
fn from(expected: ExpectedValid<'i>) -> Box<Expected<'i, S>> {
Box::new(expected.into())
}
}
impl<'i, S> From<ExpectedValue<'i>> for Expected<'i, S>
where
S: BacktraceBuilder,
{
fn from(err: ExpectedValue<'i>) -> Self {
Self::from_kind(ExpectedKind::Value(err))
}
}
#[cfg(feature = "alloc")]
impl<'i, S> From<ExpectedValue<'i>> for Box<Expected<'i, S>>
where
S: BacktraceBuilder,
{
fn from(expected: ExpectedValue<'i>) -> Box<Expected<'i, S>> {
Box::new(expected.into())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(all(target_pointer_width = "64", not(feature = "full-backtrace")))]
fn test_expected_size() {
assert_eq!(core::mem::size_of::<Expected<'_>>(), 192);
}
#[test]
#[cfg(all(target_pointer_width = "64", feature = "full-backtrace"))]
fn test_expected_size() {
assert_eq!(core::mem::size_of::<Expected<'_>>(), 216);
}
}