use super::*;
use core::hint::unreachable_unchecked;
use core::num::NonZeroUsize;
#[derive(Clone)]
pub struct ErrorImpl {
origin_info: PackedOriginInfo,
#[cfg(feature = "repr_unboxed_location")]
original_location: &'static Location<'static>,
}
impl ErrorImplFunctions for ErrorImpl {
type FrameIter<'a> = ErrorImplIter;
#[cfg_attr(feature = "repr_unboxed_location", track_caller)]
#[inline(never)]
fn new(source: ErrorOrigin, _args: Option<&Arguments<'_>>) -> ErrorImpl {
ErrorImpl {
origin_info: PackedOriginInfo::for_origin(source),
#[cfg(feature = "repr_unboxed_location")]
original_location: Location::caller(),
}
}
#[inline(never)]
fn push_context(&mut self, source: &'static ErrorInfoImpl, _args: Option<&Arguments<'_>>) {
self.origin_info = self.origin_info.with_context(source);
}
fn code(&self) -> Option<&'static ErrorCodeInfo> {
self.origin_info.code()
}
fn iter(&self) -> Self::FrameIter<'_> {
ErrorImplIter {
phase: ErrorIterPhase::LastContext,
origin_info: self.origin_info,
#[cfg(feature = "repr_unboxed_location")]
original_location: Some(self.original_location),
#[cfg(not(feature = "repr_unboxed_location"))]
original_location: None,
}
}
}
const TAG_STATIC_ORIGINAL: usize = 0;
const TAG_STATIC_TYPE_ONLY: usize = 1;
const TAG_STATIC_CONTEXT_ONLY: usize = 2;
const TAG_MASK: usize = 0b11;
const MAX_TYPE_LEN: usize = (usize::MAX >> 2) + 1;
const OMITTED_BIT_MASK: usize = 0b1;
#[derive(Copy, Clone)]
struct PackedOriginInfo {
tag: NonZeroUsize,
additional: usize,
}
impl PackedOriginInfo {
fn for_origin(e: ErrorOrigin) -> Self {
unsafe {
match e {
ErrorOrigin::StaticOrigin(ptr) | ErrorOrigin::TypeOrigin(_, Some(ptr)) => {
PackedOriginInfo {
tag: NonZeroUsize::new_unchecked(
(ptr as *const _ as usize) | TAG_STATIC_ORIGINAL,
),
additional: 0,
}
}
ErrorOrigin::TypeOrigin(ptr, None) => {
assert!(ptr.len() < MAX_TYPE_LEN);
PackedOriginInfo {
tag: NonZeroUsize::new_unchecked((ptr.len() << 2) | TAG_STATIC_TYPE_ONLY),
additional: ptr.as_ptr() as usize,
}
}
}
}
}
fn tag(&self) -> usize {
self.tag.get() & TAG_MASK
}
fn with_context(mut self, source: &'static ErrorInfoImpl) -> Self {
unsafe {
match self.tag() {
TAG_STATIC_ORIGINAL | TAG_STATIC_CONTEXT_ONLY => {
if self.additional == 0 {
self.additional = source as *const _ as usize;
self
} else {
let original = &*(self.additional as *const ErrorInfoImpl);
if original.error_code.is_none() || source.error_code.is_some() {
self.additional = source as *const _ as usize;
self.additional |= OMITTED_BIT_MASK;
self
} else {
self.additional |= OMITTED_BIT_MASK;
self
}
}
}
TAG_STATIC_TYPE_ONLY => PackedOriginInfo {
tag: NonZeroUsize::new_unchecked(
(source as *const _ as usize) | TAG_STATIC_CONTEXT_ONLY,
),
additional: 0,
},
_ => unreachable_unchecked(),
}
}
}
fn ty_name(&self) -> &'static str {
unsafe {
assert_eq!(self.tag(), TAG_STATIC_TYPE_ONLY);
let ptr = self.additional as *const u8;
let len = self.tag.get() >> 2;
let slice = core::slice::from_raw_parts(ptr, len);
core::str::from_utf8_unchecked(slice)
}
}
fn context_first(&self) -> &'static ErrorInfoImpl {
unsafe {
assert!(self.tag() == TAG_STATIC_ORIGINAL || self.tag() == TAG_STATIC_CONTEXT_ONLY);
&*((self.tag.get() & !TAG_MASK) as *const ErrorInfoImpl)
}
}
fn context_second(&self) -> Option<&'static ErrorInfoImpl> {
unsafe {
assert!(self.tag() == TAG_STATIC_ORIGINAL || self.tag() == TAG_STATIC_CONTEXT_ONLY);
if (self.additional & !OMITTED_BIT_MASK) == 0 {
None
} else {
Some(&*((self.additional & !OMITTED_BIT_MASK) as *const ErrorInfoImpl))
}
}
}
fn has_omitted_context(self) -> bool {
if self.tag() == TAG_STATIC_CONTEXT_ONLY || self.tag() == TAG_STATIC_ORIGINAL {
self.additional & OMITTED_BIT_MASK == OMITTED_BIT_MASK
} else {
false
}
}
#[inline(never)]
fn code(&self) -> Option<&'static ErrorCodeInfo> {
if self.tag() == TAG_STATIC_TYPE_ONLY {
None
} else {
if let Some(context_second) = self.context_second() {
if context_second.error_code.is_some() {
return context_second.error_code;
}
}
self.context_first().error_code
}
}
}
pub struct ErrorImplIter {
phase: ErrorIterPhase,
origin_info: PackedOriginInfo,
original_location: Option<&'static Location<'static>>,
}
#[derive(Copy, Clone, Eq, PartialEq)]
enum ErrorIterPhase {
LastContext,
FirstContext,
LocationMismatchFrame,
TypeContext,
FramesOmitted,
Ended,
}
impl Iterator for ErrorImplIter {
type Item = ErrorFrameImpl;
fn next(&mut self) -> Option<Self::Item> {
let tag = self.origin_info.tag();
if self.phase == ErrorIterPhase::LastContext {
self.phase = ErrorIterPhase::FirstContext;
if tag == TAG_STATIC_ORIGINAL || tag == TAG_STATIC_CONTEXT_ONLY {
if let Some(context_second) = self.origin_info.context_second() {
return Some(ErrorFrameImpl {
data: ErrorFrameData::decode_static(Some(context_second), None),
location: context_second.location.map(|x| *x),
});
}
}
}
if self.phase == ErrorIterPhase::FirstContext {
self.phase = ErrorIterPhase::LocationMismatchFrame;
if tag == TAG_STATIC_ORIGINAL || tag == TAG_STATIC_CONTEXT_ONLY {
let context_first = self.origin_info.context_first();
let location = if tag == TAG_STATIC_ORIGINAL {
self.original_location
.map(DecodedLocation::from)
.or_else(|| context_first.location.map(|x| *x))
} else {
context_first.location.map(|x| *x)
};
return Some(ErrorFrameImpl {
data: ErrorFrameData::decode_static(Some(context_first), None),
location,
});
}
}
if self.phase == ErrorIterPhase::LocationMismatchFrame {
self.phase = ErrorIterPhase::TypeContext;
if tag == TAG_STATIC_ORIGINAL {
let context_first = self.origin_info.context_first();
if let Some(location_a) = context_first.location
&& let Some(location_b) = self.original_location
{
if !location_a.is_same(location_b.into()) {
return Some(ErrorFrameImpl {
data: ErrorFrameData::InternalContext(
InternalContextType::ErrorTypeConstructed,
),
location: Some(*location_a),
});
}
}
}
}
if self.phase == ErrorIterPhase::TypeContext {
self.phase = ErrorIterPhase::FramesOmitted;
if tag == TAG_STATIC_TYPE_ONLY {
return Some(ErrorFrameImpl {
data: ErrorFrameData::TypeFrame(self.origin_info.ty_name(), None),
location: self.original_location.map(DecodedLocation::from),
});
} else if tag == TAG_STATIC_CONTEXT_ONLY {
return Some(ErrorFrameImpl {
data: ErrorFrameData::InternalContext(InternalContextType::OriginalTypeLost),
location: self.original_location.map(DecodedLocation::from),
});
}
}
if self.phase == ErrorIterPhase::FramesOmitted {
self.phase = ErrorIterPhase::Ended;
if tag == TAG_STATIC_ORIGINAL || tag == TAG_STATIC_CONTEXT_ONLY {
if self.origin_info.has_omitted_context() {
return Some(ErrorFrameImpl {
data: ErrorFrameData::InternalContext(
InternalContextType::FurtherFramesOmitted,
),
location: None,
});
}
}
}
None
}
}
const _CHECK_REQUIRED_ALIGNMENT: () = {
let required_alignment = 4;
assert!(align_of::<ErrorInfoImpl>() >= required_alignment);
};