tracing_tunnel/
value.rs
1use serde::{Deserialize, Serialize};
4
5use core::{borrow::Borrow, fmt};
6
7use crate::alloc::{format, String, ToOwned};
8
9#[cfg(feature = "std")]
10mod error {
11 use serde::{Deserialize, Serialize};
12
13 use std::{error, fmt};
14
15 #[derive(Debug, Clone, Serialize, Deserialize)]
17 #[non_exhaustive]
18 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
19 pub struct TracedError {
20 pub message: String,
22 pub source: Option<Box<TracedError>>,
24 }
25
26 impl TracedError {
27 pub(super) fn new(err: &(dyn error::Error + 'static)) -> Self {
28 Self {
29 message: err.to_string(),
30 source: err.source().map(|source| Box::new(Self::new(source))),
31 }
32 }
33 }
34
35 impl fmt::Display for TracedError {
36 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
37 formatter.write_str(&self.message)
38 }
39 }
40
41 impl error::Error for TracedError {
42 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
43 self.source
44 .as_ref()
45 .map(|source| source.as_ref() as &(dyn error::Error + 'static))
46 }
47 }
48}
49
50#[cfg(feature = "std")]
51pub use self::error::TracedError;
52
53#[derive(Clone, Serialize, Deserialize)]
56#[serde(transparent)]
57pub struct DebugObject(String);
58
59impl fmt::Debug for DebugObject {
60 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
61 formatter.write_str(&self.0)
62 }
63}
64
65impl AsRef<str> for DebugObject {
67 fn as_ref(&self) -> &str {
68 &self.0
69 }
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize)]
74#[serde(rename_all = "snake_case")]
75#[non_exhaustive]
76pub enum TracedValue {
77 Bool(bool),
79 Int(i128),
81 UInt(u128),
83 Float(f64),
85 String(String),
87 Object(DebugObject),
89 #[cfg(feature = "std")]
91 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
92 Error(TracedError),
93}
94
95impl TracedValue {
96 #[doc(hidden)] pub fn debug(object: &dyn fmt::Debug) -> Self {
98 Self::Object(DebugObject(format!("{object:?}")))
99 }
100
101 #[inline]
103 pub fn as_bool(&self) -> Option<bool> {
104 bool::from_value(self)
105 }
106
107 #[inline]
109 pub fn as_int(&self) -> Option<i128> {
110 i128::from_value(self)
111 }
112
113 #[inline]
115 pub fn as_uint(&self) -> Option<u128> {
116 u128::from_value(self)
117 }
118
119 #[inline]
121 pub fn as_float(&self) -> Option<f64> {
122 f64::from_value(self)
123 }
124
125 #[inline]
127 pub fn as_str(&self) -> Option<&str> {
128 str::from_value(self)
129 }
130
131 pub fn is_debug(&self, object: &dyn fmt::Debug) -> bool {
134 match self {
135 Self::Object(value) => value.0 == format!("{object:?}"),
136 _ => false,
137 }
138 }
139
140 pub fn as_debug_str(&self) -> Option<&str> {
143 match self {
144 Self::Object(value) => Some(&value.0),
145 _ => None,
146 }
147 }
148
149 #[cfg(feature = "std")]
150 pub(crate) fn error(err: &(dyn std::error::Error + 'static)) -> Self {
151 Self::Error(TracedError::new(err))
152 }
153}
154
155pub trait FromTracedValue<'a> {
157 type Output: Borrow<Self> + 'a;
159 fn from_value(value: &'a TracedValue) -> Option<Self::Output>;
161}
162
163impl<'a> FromTracedValue<'a> for str {
164 type Output = &'a str;
165
166 fn from_value(value: &'a TracedValue) -> Option<Self::Output> {
167 match value {
168 TracedValue::String(value) => Some(value),
169 _ => None,
170 }
171 }
172}
173
174macro_rules! impl_value_conversions {
175 (TracedValue :: $variant:ident ($source:ty)) => {
176 impl From<$source> for TracedValue {
177 fn from(value: $source) -> Self {
178 Self::$variant(value)
179 }
180 }
181
182 impl PartialEq<$source> for TracedValue {
183 fn eq(&self, other: &$source) -> bool {
184 match self {
185 Self::$variant(value) => value == other,
186 _ => false,
187 }
188 }
189 }
190
191 impl PartialEq<TracedValue> for $source {
192 fn eq(&self, other: &TracedValue) -> bool {
193 other == self
194 }
195 }
196
197 impl FromTracedValue<'_> for $source {
198 type Output = Self;
199
200 fn from_value(value: &TracedValue) -> Option<Self::Output> {
201 match value {
202 TracedValue::$variant(value) => Some(*value),
203 _ => None,
204 }
205 }
206 }
207 };
208
209 (TracedValue :: $variant:ident ($source:ty as $field_ty:ty)) => {
210 impl From<$source> for TracedValue {
211 fn from(value: $source) -> Self {
212 Self::$variant(value.into())
213 }
214 }
215
216 impl PartialEq<$source> for TracedValue {
217 fn eq(&self, other: &$source) -> bool {
218 match self {
219 Self::$variant(value) => *value == <$field_ty>::from(*other),
220 _ => false,
221 }
222 }
223 }
224
225 impl PartialEq<TracedValue> for $source {
226 fn eq(&self, other: &TracedValue) -> bool {
227 other == self
228 }
229 }
230
231 impl FromTracedValue<'_> for $source {
232 type Output = Self;
233
234 fn from_value(value: &TracedValue) -> Option<Self::Output> {
235 match value {
236 TracedValue::$variant(value) => (*value).try_into().ok(),
237 _ => None,
238 }
239 }
240 }
241 };
242}
243
244impl_value_conversions!(TracedValue::Bool(bool));
245impl_value_conversions!(TracedValue::Int(i128));
246impl_value_conversions!(TracedValue::Int(i64 as i128));
247impl_value_conversions!(TracedValue::UInt(u128));
248impl_value_conversions!(TracedValue::UInt(u64 as u128));
249impl_value_conversions!(TracedValue::Float(f64));
250
251impl PartialEq<str> for TracedValue {
252 fn eq(&self, other: &str) -> bool {
253 match self {
254 Self::String(value) => value == other,
255 _ => false,
256 }
257 }
258}
259
260impl PartialEq<TracedValue> for str {
261 fn eq(&self, other: &TracedValue) -> bool {
262 other == self
263 }
264}
265
266impl From<&str> for TracedValue {
267 fn from(value: &str) -> Self {
268 Self::String(value.to_owned())
269 }
270}
271
272impl PartialEq<&str> for TracedValue {
273 fn eq(&self, other: &&str) -> bool {
274 match self {
275 Self::String(value) => value == *other,
276 _ => false,
277 }
278 }
279}
280
281impl PartialEq<TracedValue> for &str {
282 fn eq(&self, other: &TracedValue) -> bool {
283 other == self
284 }
285}