scale_value/scale_impls/tracing_decoder/
error.rs1use super::path::Path;
17use crate::prelude::*;
18use crate::scale::DecodeError;
19use crate::string_impls::format_hex;
20use crate::Value;
21use core::fmt::Write;
22
23#[derive(Clone, Debug)]
25pub struct TraceDecodingError<Val> {
26 inner: TraceDecodingErrorInner<Val>,
27}
28
29impl<Val> TraceDecodingError<Val> {
30 pub(crate) fn map_decoded_so_far<NewVal>(
31 self,
32 f: impl FnOnce(Val) -> NewVal,
33 ) -> TraceDecodingError<NewVal> {
34 match self.inner {
35 TraceDecodingErrorInner::FromDecodeError(e) => {
36 TraceDecodingErrorInner::FromDecodeError(e).into()
37 }
38 TraceDecodingErrorInner::FromVisitor(e) => {
39 TraceDecodingErrorInner::FromVisitor(VisitorError {
40 at: e.at,
41 decode_error: e.decode_error,
42 decoded_so_far: f(e.decoded_so_far),
43 })
44 .into()
45 }
46 }
47 }
48 pub(crate) fn with_outer_context<NewVal>(
49 self,
50 outer_path: impl FnOnce() -> Path,
51 default_outer_value: impl FnOnce() -> NewVal,
52 into_outer_value: impl FnOnce(Val) -> NewVal,
53 ) -> TraceDecodingError<NewVal> {
54 match self.inner {
55 TraceDecodingErrorInner::FromDecodeError(e) => {
56 TraceDecodingErrorInner::FromVisitor(VisitorError {
57 at: outer_path(),
58 decoded_so_far: default_outer_value(),
59 decode_error: e,
60 })
61 .into()
62 }
63 TraceDecodingErrorInner::FromVisitor(e) => {
64 TraceDecodingErrorInner::FromVisitor(VisitorError {
65 at: e.at,
66 decoded_so_far: into_outer_value(e.decoded_so_far),
67 decode_error: e.decode_error,
68 })
69 .into()
70 }
71 }
72 }
73}
74
75impl<Val> From<TraceDecodingErrorInner<Val>> for TraceDecodingError<Val> {
76 fn from(value: TraceDecodingErrorInner<Val>) -> Self {
77 TraceDecodingError { inner: value }
78 }
79}
80
81#[derive(Clone, Debug)]
82enum TraceDecodingErrorInner<Val> {
83 FromDecodeError(DecodeError),
84 FromVisitor(VisitorError<Val>),
85}
86
87#[derive(Clone, Debug)]
88struct VisitorError<Val> {
89 at: Path,
90 decoded_so_far: Val,
91 decode_error: DecodeError,
92}
93
94impl<Ctx: core::fmt::Debug> core::fmt::Display for TraceDecodingError<Value<Ctx>> {
95 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
96 match &self.inner {
97 TraceDecodingErrorInner::FromDecodeError(e) => {
98 write!(f, "Error decoding value: {e}")
99 }
100 TraceDecodingErrorInner::FromVisitor(e) => {
101 write!(
102 f,
103 "Error decoding value at {}: {}\nDecoded so far:\n\n",
104 e.at, e.decode_error,
105 )?;
106 display_value_with_typeid(f, &e.decoded_so_far)
107 }
108 }
109 }
110}
111
112impl<Ctx: core::fmt::Debug> core::error::Error for TraceDecodingError<Value<Ctx>> {}
113
114impl<TypeId> From<DecodeError> for TraceDecodingError<TypeId> {
115 fn from(value: DecodeError) -> Self {
116 TraceDecodingErrorInner::FromDecodeError(value).into()
117 }
118}
119
120impl<TypeId> From<codec::Error> for TraceDecodingError<TypeId> {
121 fn from(value: codec::Error) -> Self {
122 TraceDecodingErrorInner::FromDecodeError(value.into()).into()
123 }
124}
125
126fn display_value_with_typeid<Id: core::fmt::Debug>(
127 f: &mut core::fmt::Formatter<'_>,
128 value: &Value<Id>,
129) -> core::fmt::Result {
130 crate::string_impls::ToWriterBuilder::new()
131 .pretty()
132 .format_context(|type_id, writer: &mut &mut core::fmt::Formatter| {
133 write!(writer, "{type_id:?}")
134 })
135 .add_custom_formatter(|value, writer| format_hex(value, writer))
136 .write(value, f)
137}