1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
mod frame_impl;
mod kind;

use alloc::boxed::Box;
#[cfg(nightly)]
use core::any::{self, Demand, Provider};
use core::{any::TypeId, fmt, panic::Location};

use self::frame_impl::FrameImpl;
pub use self::kind::{AttachmentKind, FrameKind};

/// A single context or attachment inside of a [`Report`].
///
/// `Frame`s are organized as a singly linked list, which can be iterated by calling
/// [`Report::frames()`]. The head contains the current context or attachment, and the tail contains
/// the root context created by [`Report::new()`]. The next `Frame` can be accessed by requesting it
/// by calling [`Report::request_ref()`].
///
/// [`Report`]: crate::Report
/// [`Report::frames()`]: crate::Report::frames
/// [`Report::new()`]: crate::Report::new
/// [`Report::request_ref()`]: crate::Report::request_ref
pub struct Frame {
    frame: Box<dyn FrameImpl>,
    location: &'static Location<'static>,
    sources: Box<[Frame]>,
}

impl Frame {
    /// Returns the location where this `Frame` was created.
    #[must_use]
    #[deprecated(
        since = "0.2.4",
        note = "`location()` has been replaced with an additional attachment containing \
                `Location<'static>` for each `Context`, similar to how `Backtrace` and \
                `SpanTrace` are handled. Note: This means that once `location()` is removed you \
                won't be able to get location of attachments anymore."
    )]
    pub const fn location(&self) -> &'static Location<'static> {
        self.location
    }

    #[allow(missing_docs)]
    #[must_use]
    #[deprecated(since = "0.2.0", note = "use `sources()` instead")]
    pub const fn source(&self) -> Option<&Self> {
        self.sources().first()
    }

    /// Returns a shared reference to the source of this `Frame`.
    ///
    /// This corresponds to the `Frame` below this one in a [`Report`].
    ///
    /// [`Report`]: crate::Report
    #[must_use]
    pub const fn sources(&self) -> &[Self] {
        &self.sources
    }

    #[allow(missing_docs)]
    #[must_use]
    #[deprecated(since = "0.2.0", note = "use `sources_mut()` instead")]
    pub fn source_mut(&mut self) -> Option<&mut Self> {
        self.sources_mut().first_mut()
    }

    /// Returns a mutable reference to the sources of this `Frame`.
    ///
    /// This corresponds to the `Frame` below this one in a [`Report`].
    ///
    /// [`Report`]: crate::Report
    #[must_use]
    pub fn sources_mut(&mut self) -> &mut [Self] {
        &mut self.sources
    }

    /// Returns how the `Frame` was created.
    #[must_use]
    pub fn kind(&self) -> FrameKind<'_> {
        self.frame.kind()
    }

    /// Requests the reference to `T` from the `Frame` if provided.
    #[must_use]
    #[cfg(nightly)]
    pub fn request_ref<T>(&self) -> Option<&T>
    where
        T: ?Sized + 'static,
    {
        any::request_ref(self)
    }

    /// Requests the value of `T` from the `Frame` if provided.
    #[must_use]
    #[cfg(nightly)]
    pub fn request_value<T>(&self) -> Option<T>
    where
        T: 'static,
    {
        any::request_value(self)
    }

    /// Returns if `T` is the held context or attachment by this frame.
    #[must_use]
    pub fn is<T: Send + Sync + 'static>(&self) -> bool {
        self.frame.as_any().is::<T>()
    }

    /// Downcasts this frame if the held context or attachment is the same as `T`.
    #[must_use]
    pub fn downcast_ref<T: Send + Sync + 'static>(&self) -> Option<&T> {
        self.frame.as_any().downcast_ref()
    }

    /// Downcasts this frame if the held context or attachment is the same as `T`.
    #[must_use]
    pub fn downcast_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
        self.frame.as_any_mut().downcast_mut()
    }

    /// Returns the [`TypeId`] of the held context or attachment by this frame.
    #[must_use]
    pub fn type_id(&self) -> TypeId {
        self.frame.as_any().type_id()
    }
}

#[cfg(nightly)]
impl Provider for Frame {
    fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
        self.frame.provide(demand);
    }
}

impl fmt::Debug for Frame {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut debug = fmt.debug_struct("Frame");

        match self.kind() {
            FrameKind::Context(context) => {
                debug.field("context", &context);
                debug.finish()
            }
            FrameKind::Attachment(AttachmentKind::Printable(attachment)) => {
                debug.field("attachment", &attachment);
                debug.finish()
            }
            FrameKind::Attachment(AttachmentKind::Opaque(_)) => debug.finish_non_exhaustive(),
        }
    }
}