MCRO
C++23 utilities for Unreal Engine.
Loading...
Searching...
No Matches
Error.h
Go to the documentation of this file.
1/** @noop License Comment
2 * @file
3 * @copyright
4 * This Source Code is subject to the terms of the Mozilla Public License, v2.0.
5 * If a copy of the MPL was not distributed with this file You can obtain one at
6 * https://mozilla.org/MPL/2.0/
7 *
8 * @author David Mórász
9 * @date 2025
10 */
11
12#pragma once
13
14#include "CoreMinimal.h"
15#include "Mcro/Error.Fwd.h"
16#include "Void.h"
17#include "Mcro/Types.h"
18#include "Mcro/Concepts.h"
19#include "Mcro/SharedObjects.h"
20#include "Mcro/Observable.Fwd.h"
21
23#include "yaml-cpp/yaml.h"
25
26#include <source_location>
27
28/** Contains utilities for structured error handling */
29namespace Mcro::Error
30{
31 using namespace Mcro::Text;
32 using namespace Mcro::Types;
33 using namespace Mcro::FunctionTraits;
34 using namespace Mcro::SharedObjects;
35
36 /**
37 * A base class for a structured error handling and reporting with modular architecture and fluent API.
38 *
39 * @important
40 * Instantiate errors only with `IError::Make(new FMyError())` this ensures the minimal runtime reflection features.
41 *
42 * @remarks
43 * Many times runtime errors are unavoidable and if an API only gives indication of success or failure (let's say in
44 * the form of a boolean) that will be quite frustrating for the user to report, as it gives no direction of course
45 * what went wrong, how it went wrong, and when it went wrong. Slightly better when the API gives a list of things
46 * what can go wrong and return an item from that list when things go wrong. This of course still doesn't allow to
47 * provide much of a context for the user.
48 * @remarks
49 * An 'improvement' to that is using C++ exceptions, however it is not unanimously well received in the community
50 * because it can hide the fact that the API can bail on its caller. So when exceptions are enabled one may call
51 * every function of an API like if they were walking on a minefield. For this (and a couple more) reasons C++
52 * exceptions are disabled by default in Unreal projects and viewed as terrible practice to introduce it ourselves.
53 * @remarks
54 * Unreal does provide though the `TValueOrError` template which allows API's to indicate that they can fail in some
55 * ways without the need to consult an external documentation. It gives the developer total freedom however of what
56 * the error can be, so on its own it does not solve the questions of what/when/how.
57 * @remarks
58 * Using `TMaybe` with `IError` can be a powerful tool in the developer's arsenal when creating a library.
59 * `IError` can standardize a detailed and structured way of communicating errors without hindering call-site
60 * usage. It can also automate the method and the format of logging the (many times excessive amount of)
61 * information surrounding an error, or decide how it may be presented for the user.
62 */
63 class MCRO_API IError : public IHaveType
64 {
65 protected:
66 TMap<FString, IErrorRef> InnerErrors;
67 TArray<std::source_location> ErrorPropagation;
68 EErrorSeverity Severity = EErrorSeverity::ErrorComponent;
69 FString Message;
70 FString Details;
71 FString CodeContext;
72
73 /** Override this method if inner errors needs custom way of serialization */
74 virtual void SerializeInnerErrors(YAML::Emitter& emitter) const;
75
76 /** Override this method if error propagation history needs custom way of serialization */
77 virtual void SerializeErrorPropagation(YAML::Emitter& emitter) const;
78
79 /** Override this method if inner errors added to current one needs special attention */
80 virtual void AddError(const FString& name, const TSharedRef<IError>& error, const FString& typeOverride = {});
81
82 /** Add extra separate blocks of text in an ad-hoc fashion */
83 virtual void AddAppendix(const FString& name, const FString& text, const FString& type = TEXT("Appendix"));
84
85 void AddCppStackTrace(const FString& name, int32 numAdditionalStackFramesToIgnore, bool fastWalk);
86 void AddBlueprintStackTrace(const FString& name);
87
88 /**
89 * Override this method if direct members should be serialized differently or extra members are added by
90 * derived errors.
91 */
92 virtual void SerializeMembers(YAML::Emitter& emitter, bool isRoot) const;
93
95
96 public:
97
98 FORCEINLINE decltype(InnerErrors)::TRangedForIterator begin() { return InnerErrors.begin(); }
99 FORCEINLINE decltype(InnerErrors)::TRangedForConstIterator begin() const { return InnerErrors.begin(); }
100 FORCEINLINE decltype(InnerErrors)::TRangedForIterator end() { return InnerErrors.end(); }
101 FORCEINLINE decltype(InnerErrors)::TRangedForConstIterator end() const { return InnerErrors.end(); }
102
103 /**
104 * This is an empty function so any `IError` can fulfill `CSharedInitializeable` without needing extra
105 * attention in derived classes. Simply hide this function with overloads in derived classes if they need
106 * to use TSharedFromThis for initioalization
107 */
108 void Initialize() {};
109
110 /**
111 * Override this function to change the method how this error is entirely serialized into a YAML format
112 * @param emitter the YAML node into which the data of this error needs to be appended to
113 * @param isRoot true when the top level error is being serialized
114 */
115 virtual void SerializeYaml(YAML::Emitter& emitter, bool isRoot) const;
116
117 /** Render this error as a string using the YAML representation */
118 FString ToString() const;
119
120 /** Render this error as a std::string using the YAML representation */
121 std::string ToStringUtf8() const;
122
123 /**
124 * To ensure automatic type reflection use IError::Make instead of manually constructing error objects
125 * @code
126 * IError::Make(new FMyError(myConstructorArgs), myInitializerArgs);
127 * @endcode
128 * @tparam T Type of new error
129 * @tparam Args Arguments for the new error initializer.
130 * @param newError Pass the new object in as `new FMyError(...)`
131 * @param args Arguments for the new error initializer.
132 * @return
133 */
134 template <CError T, typename... Args>
135 requires CSharedInitializeable<T, Args...>
136 static TSharedRef<T> Make(T* newError, Args&&... args)
137 {
138 return MakeShareableInit(newError, Forward<Args>(args)...)->WithType();
139 }
140
141 FORCEINLINE EErrorSeverity GetSeverity() const { return Severity; }
142 FORCEINLINE int32 GetSeverityInt() const { return static_cast<int32>(Severity); }
143 FORCEINLINE FString const& GetMessage() const { return Message; }
144 FORCEINLINE FString const& GetDetails() const { return Details; }
145 FORCEINLINE FString const& GetCodeContext() const { return CodeContext; }
146 FORCEINLINE TMap<FString, IErrorRef> const& GetInnerErrors() const { return InnerErrors; }
147 FORCEINLINE int32 GetInnerErrorCount() const { return InnerErrors.Num(); }
148
149 /**
150 * Get a list of source locations where this error has been handled. This is not equivalent of stack-traces but
151 * rather a historical record of where this error was considered throughout the source code. Each item in this
152 * list is explicitly recorded via `WithLocation`. The first item is the earliest consideration of this error.
153 */
154 TArray<FString> GetErrorPropagation() const;
155
156 /** Same as `GetErrorPropagation` but items are separated by new line. */
158
159 /** Get the error severity as an unreal string. */
160 FStringView GetSeverityString() const;
161
162 /** Override this function to customize how an error is displaxed for the end-user */
163 virtual TSharedRef<SErrorDisplay> CreateErrorWidget();
164
165 /**
166 * Specify error message with a fluent API
167 * @tparam Self Deducing this
168 * @param self Deduced this (not present in calling arguments)
169 * @param input the message
170 * @param condition Only add message when this condition is satisfied
171 * @return Self for further fluent API setup
172 */
173 template <typename Self>
174 SelfRef<Self> WithMessage(this Self&& self, const FString& input, bool condition = true)
175 {
176 if (condition) self.Message = input;
177 return self.SharedThis(&self);
178 }
179
180 /**
181 * Specify formatted error message with a fluent API
182 * @tparam Self Deducing this
183 * @param self Deduced this (not present in calling arguments)
184 * @param input the message format
185 * @param fmtArgs format arguments
186 * @return Self for further fluent API setup
187 */
188 template <typename Self, typename... FormatArgs>
189 SelfRef<Self> WithMessageF(this Self&& self, const TCHAR* input, FormatArgs&&... fmtArgs)
190 {
191 self.Message = DynamicPrintf(input, Forward<FormatArgs>(fmtArgs)...);
192 return self.SharedThis(&self);
193 }
194
195 /**
196 * Specify formatted error message with a fluent API
197 * @tparam Self Deducing this
198 * @param self Deduced this (not present in calling arguments)
199 * @param condition Only add message when this condition is satisfied
200 * @param input the message format
201 * @param fmtArgs format arguments
202 * @return Self for further fluent API setup
203 */
204 template <typename Self, typename... FormatArgs>
205 SelfRef<Self> WithMessageFC(this Self&& self, bool condition, const TCHAR* input, FormatArgs&&... fmtArgs)
206 {
207 if (condition) self.Message = DynamicPrintf(input, Forward<FormatArgs>(fmtArgs)...);
208 return self.SharedThis(&self);
209 }
210
211 /**
212 * Specify severity with a fluent API
213 * @tparam Self Deducing this
214 * @param self Deduced this (not present in calling arguments)
215 * @param input the severity
216 * @return Self for further fluent API setup
217 * @see Mcro::Error::EErrorSeverity
218 */
219 template <typename Self>
221 {
222 self.Severity = input;
223 return self.SharedThis(&self);
224 }
225
226 /** Recoverable shorthand */
227 template <typename Self>
228 SelfRef<Self> AsRecoverable(this Self&& self)
229 {
230 self.Severity = EErrorSeverity::Recoverable;
231 return self.SharedThis(&self);
232 }
233
234 /** Fatal shorthand */
235 template <typename Self>
236 SelfRef<Self> AsFatal(this Self&& self)
237 {
238 self.Severity = EErrorSeverity::Fatal;
239 return self.SharedThis(&self);
240 }
241
242 /** Crashing shorthand */
243 template <typename Self>
244 SelfRef<Self> AsCrashing(this Self&& self)
245 {
246 self.Severity = EErrorSeverity::Crashing;
247 return self.SharedThis(&self);
248 }
249
250 /**
251 * Specify details for the error which may provide further context for the user or provide them
252 * reminders/suggestions
253 * @tparam Self Deducing this
254 * @param self Deduced this (not present in calling arguments)
255 * @param input the details text
256 * @param condition Only add details when this condition is satisfied
257 * @return Self for further fluent API setup
258 */
259 template <typename Self>
260 SelfRef<Self> WithDetails(this Self&& self, const FString& input, bool condition = true)
261 {
262 if (condition) self.Details = input;
263 return self.SharedThis(&self);
264 }
265
266 /**
267 * Specify formatted details for the error which may provide further context for the user or provide them
268 * reminders/suggestions
269 * @tparam Self Deducing this
270 * @param self Deduced this (not present in calling arguments)
271 * @param input the details text
272 * @param fmtArgs format arguments
273 * @return Self for further fluent API setup
274 */
275 template <typename Self, typename... FormatArgs>
276 SelfRef<Self> WithDetailsF(this Self&& self, const TCHAR* input, FormatArgs&&... fmtArgs)
277 {
278 self.Details = DynamicPrintf(input, Forward<FormatArgs>(fmtArgs)...);
279 return self.SharedThis(&self);
280 }
281
282 /**
283 * Specify formatted details for the error which may provide further context for the user or provide them
284 * reminders/suggestions
285 * @tparam Self Deducing this
286 * @param self Deduced this (not present in calling arguments)
287 * @param input the details text
288 * @param condition Only add details when this condition is satisfied
289 * @param fmtArgs format arguments
290 * @return Self for further fluent API setup
291 */
292 template <typename Self, typename... FormatArgs>
293 SelfRef<Self> WithDetailsFC(this Self&& self, bool condition, const TCHAR* input, FormatArgs&&... fmtArgs)
294 {
295 if (condition) self.Details = DynamicPrintf(input, Forward<FormatArgs>(fmtArgs)...);
296 return self.SharedThis(&self);
297 }
298
299 /**
300 * If available write a source code context into the error directly displaying where this error has occured
301 * @tparam Self Deducing this
302 * @param self Deduced this (not present in calling arguments)
303 * @param input the source code context
304 * @param condition Only add code context when this condition is satisfied
305 * @return Self for further fluent API setup
306 */
307 template <typename Self>
308 SelfRef<Self> WithCodeContext(this Self&& self, const FString& input, bool condition = true)
309 {
310 if (condition) self.CodeContext = input;
311 return self.SharedThis(&self);
312 }
313
314 /**
315 * Add a uniquely typed inner error.
316 * @tparam Self Deducing this
317 * @tparam Error Deduced type of the error
318 * @param self Deduced this (not present in calling arguments)
319 * @param input Inner error
320 * @param condition Only add inner error when this condition is satisfied
321 * @return Self for further fluent API setup
322 */
323 template <typename Self, CError Error>
324 SelfRef<Self> WithError(this Self&& self, const TSharedRef<Error>& input, bool condition = true)
325 {
326 if (condition) self.AddError({}, input);
327 return self.SharedThis(&self);
328 }
329
330 /**
331 * Add one inner error with specific name.
332 * @tparam Self Deducing this
333 * @tparam Error Deduced type of the error
334 * @param self Deduced this (not present in calling arguments)
335 * @param name Optional name of the error. If it's empty only the type of the error will be used for ID
336 * @param input Inner error
337 * @param condition Only add inner error when this condition is satisfied
338 * @return Self for further fluent API setup
339 */
340 template <typename Self, CError Error>
341 SelfRef<Self> WithError(this Self&& self, const FString& name, const TSharedRef<Error>& input, bool condition = true)
342 {
343 if (condition) self.AddError(name, input);
344 return self.SharedThis(&self);
345 }
346
347 /**
348 * Add multiple errors at once with optional names
349 * @tparam Self Deducing this
350 * @param input An array of tuples with otional error name and the error itself
351 * @param condition Only add errors when this condition is satisfied
352 * @return Self for further fluent API setup
353 */
354 template <typename Self>
355 SelfRef<Self> WithErrors(this Self&& self, const TArray<TTuple<FString, IErrorRef>>& input, bool condition = true)
356 {
357 if (condition)
358 {
359 for (const auto& error : input)
360 self.AddError(error.Key, error.Value);
361 }
362 return self.SharedThis(&self);
363 }
364
365 /**
366 * Add multiple errors at once
367 * @tparam Self Deducing this
368 * @tparam Errors Deduced type of the errors
369 * @param errors Errors to be added
370 * @return Self for further fluent API setup
371 */
372 template <typename Self, CError... Errors>
373 SelfRef<Self> WithErrors(this Self&& self, const TSharedRef<Errors>&... errors)
374 {
375 (self.AddError({}, errors), ...);
376 return self.SharedThis(&self);
377 }
378
379 /**
380 * Add multiple errors at once
381 * @tparam Self Deducing this
382 * @tparam Errors Deduced type of the errors
383 * @param errors Errors to be added
384 * @param condition Only add errors when this condition is satisfied
385 * @return Self for further fluent API setup
386 */
387 template <typename Self, CError... Errors>
388 SelfRef<Self> WithErrors(this Self&& self, bool condition, const TSharedRef<Errors>&... errors)
389 {
390 if (condition) self.WithErrors(errors...);
391 return self.SharedThis(&self);
392 }
393
394 /**
395 * Add an extra plain text block inside inner errors
396 * @tparam Self Deducing this
397 * @param name Name of the extra text block
398 * @param text Value of the extra text block
399 * @param condition Only add inner error when this condition is satisfied
400 * @return Self for further fluent API setup
401 */
402 template <typename Self>
403 SelfRef<Self> WithAppendix(this Self&& self, const FString& name, const FString& text, bool condition = true)
404 {
405 if (condition) self.AddAppendix(name, text);
406 return self.SharedThis(&self);
407 }
408
409 /**
410 * Add an extra plain text block inside inner errors
411 * @tparam Self Deducing this
412 * @param name Name of the extra text block
413 * @param text Value of the extra text block
414 * @param fmtArgs format arguments
415 * @return Self for further fluent API setup
416 */
417 template <typename Self, typename... FormatArgs>
418 SelfRef<Self> WithAppendixF(this Self&& self, const FString& name, const TCHAR* text, FormatArgs&&... fmtArgs)
419 {
420 self.AddAppendix(name, DynamicPrintf(text, Forward<FormatArgs>(fmtArgs)...));
421 return self.SharedThis(&self);
422 }
423
424 /**
425 * Add an extra plain text block inside inner errors
426 * @tparam Self Deducing this
427 * @param name Name of the extra text block
428 * @param text Value of the extra text block
429 * @param fmtArgs format arguments
430 * @param condition Only add inner error when this condition is satisfied
431 * @return Self for further fluent API setup
432 */
433 template <typename Self, typename... FormatArgs>
434 SelfRef<Self> WithAppendixFC(this Self&& self, bool condition, const FString& name, const TCHAR* text, FormatArgs&&... fmtArgs)
435 {
436 if (condition)
437 self.AddAppendix(name, DynamicPrintf(text, Forward<FormatArgs>(fmtArgs)...));
438 return self.SharedThis(&self);
439 }
440
441 /** Notify an observable state about this error */
442 template <typename Self>
444 {
445 self.NotifyState(state);
446 return self.SharedThis(&self);
447 }
448
449 /** Break if a debugger is attached when this error is created */
450 template <typename Self>
451 SelfRef<Self> BreakDebugger(this Self&& self)
452 {
454 return self.SharedThis(&self);
455 }
456
457 /** Shorthand for adding the current C++ stacktrace to this error */
458 template <typename Self>
459 SelfRef<Self> WithCppStackTrace(this Self&& self, const FString& name = {}, bool condition = true, int32 numAdditionalStackFramesToIgnore = 0, bool fastWalk = !UE_BUILD_DEBUG)
460 {
461#if !UE_BUILD_SHIPPING
462 if (condition)
463 self.AddCppStackTrace(name, numAdditionalStackFramesToIgnore + 1, fastWalk);
464#endif
465 return self.SharedThis(&self);
466 }
467
468 /** Shorthand for adding the current Blueprint stacktrace to this error */
469 template <typename Self>
470 SelfRef<Self> WithBlueprintStackTrace(this Self&& self, const FString& name = {}, bool condition = true)
471 {
472#if !UE_BUILD_SHIPPING
473 if (condition)
474 self.AddBlueprintStackTrace(name);
475#endif
476 return self.SharedThis(&self);
477 }
478
479 /**
480 * Allow the error to record the source locations it has been handled at compile time. For example this gives
481 * more information than stack-traces because it can also record where errors were handled between parallel
482 * threads.
483 * @tparam Self Deducing this
484 * @param location The location this error is handled at. In 99% of cases this should be left at the default
485 * @return Self for further fluent API setup
486 */
487 template <typename Self>
488 SelfRef<Self> WithLocation(this Self&& self, std::source_location location = std::source_location::current())
489 {
490 self.ErrorPropagation.Add(location);
491 return self.SharedThis(&self);
492 }
493 };
494
495 /** A simple error type for checking booleans. It adds no extra features to IError */
496 class MCRO_API FAssertion : public IError {};
497
498 /**
499 * A simple error type denoting that whatever is being accessed is not available like attempting to access nullptr.
500 * It adds no extra features to IError
501 */
502 class MCRO_API FUnavailable : public IError
503 {
504 public:
506 };
507
508 /**
509 * A TValueOrError alternative for IError which allows implicit conversion from values and errors (no need for
510 * `MakeError` or `MakeValue`) and is boolean testable. It also doesn't have ambiguous state such as TValueOrError
511 * has, so a TMaybe will always have either an error or a value, it will never have neither of them or both of them.
512 */
513 template <CNonVoid T>
514 struct TMaybe
515 {
516 using ValueType = T;
517
518 /**
519 * Default initializing a TMaybe while its value is not default initializable, initializes the resulting
520 * TMaybe to an erroneous state.
521 */
522 template <typename = T>
523 requires (!CDefaultInitializable<T>)
525 ->WithMessageF(
526 TEXT("TMaybe has been default initialized, but a Value of %s cannot be default initialized"),
528 )
529 ) {}
530
531 /** If T is default initializable then the default state of TMaybe will be the default value of T, and not an error */
532 template <CDefaultInitializable = T>
533 TMaybe() : Value(T{}) {}
534
535 /** Enable copy constructor for T only when T is copy constructable */
536 template <CConvertibleToDecayed<T> From, CCopyConstructible = T>
537 TMaybe(From const& value) : Value(value) {}
538
539 /** Enable move constructor for T only when T is move constructable */
540 template <CConvertibleToDecayed<T> From, CMoveConstructible = T>
541 TMaybe(From&& value) : Value(Forward<From>(value)) {}
542
543 /** Enable copy constructor for TMaybe only when T is copy constructable */
544 template <CConvertibleToDecayed<T> From, CCopyConstructible = T>
545 TMaybe(TMaybe<From> const& other) : Value(other.Value) {}
546
547 /** Enable move constructor for TMaybe only when T is move constructable */
548 template <CConvertibleToDecayed<T> From, CMoveConstructible = T>
549 TMaybe(TMaybe<From>&& other) : Value(MoveTemp(other.Value)) {}
550
551 /** Set this TMaybe to an erroneous state */
552 template <CError ErrorType>
553 TMaybe(TSharedRef<ErrorType> const& error) : Error(error) {}
554
555 bool HasValue() const { return Value.IsSet(); }
556 bool HasError() const { return Error.IsValid(); }
557
558 auto TryGetValue() -> TOptional<T>& { return Value; }
559 auto TryGetValue() const -> TOptional<T> const& { return Value; }
560
561 auto GetValue() -> T& { return Value.GetValue(); }
562 auto GetValue() const -> T const& { return Value.GetValue(); }
563
564 auto GetError() const -> IErrorPtr { return Error; }
565
566 operator bool() const { return HasValue(); }
567
568 operator TValueOrError<T, IErrorPtr>() const
569 {
570 if (HasValue())
571 return MakeValue(Value.GetValue());
572 return MakeError(Error);
573 }
574
575 private:
576 TOptional<T> Value;
577 IErrorPtr Error;
578 };
579
580 /** Indicate that an otherwise void function that it may fail with an `IError`. */
582
583 /**
584 * Syntactically same as `FCanFail` but for functions which is explicitly used to query some boolean decidable
585 * thing, and which can also provide a reason why the queried thing is false.
586 */
588
589 /** Return an FCanFail or FTrueOrReason indicating a success or truthy output */
590 FORCEINLINE FCanFail Success() { return FVoid(); }
591}
592
593#define ERROR_LOG(categoryName, verbosity, error) \
594 UE_LOG(categoryName, verbosity, TEXT("%s"), *((error) \
595 ->WithLocation() \
596 ->ToString() \
597 )) //
598
599#define ERROR_CLOG(condition, categoryName, verbosity, error) \
600 UE_CLOG(condition, categoryName, verbosity, TEXT("%s"), *((error) \
601 ->WithLocation() \
602 ->ToString() \
603 )) //
604
605/** Similar to check() macro, but return an error instead of crashing */
606#define ASSERT_RETURN(condition) \
607 if (UNLIKELY(!(condition))) \
608 return Mcro::Error::IError::Make(new Mcro::Error::FAssertion()) \
609 ->WithLocation() \
610 ->AsRecoverable() \
611 ->WithCodeContext(PREPROCESSOR_TO_TEXT(condition)) //
612
613/** Denote that a resource which is asked for doesn't exist */
614#define UNAVAILABLE() \
615 return Mcro::Error::IError::Make(new Mcro::Error::FUnavailable()) \
616 ->WithLocation() \
617 ->AsRecoverable() //
618
619/**
620 * If a function returns a TMaybe<V> inside another function which may also return another error use this convenience
621 * macro to propagate the failure. Set a target variable name to store a returned value upon success. Leave type
622 * argument empty for existing variables
623 */
624#define PROPAGATE_FAIL_TV(type, var, expression) \
625 type var = (expression); \
626 if (UNLIKELY(var.HasError())) return var.GetError() \
627 ->WithLocation() //
628
629/**
630 * If a function returns a TMaybe<V> inside another function which may also return another error use this convenience
631 * macro to propagate the failure. Set a local variable to store a returned value upon success.
632 */
633#define PROPAGATE_FAIL_V(var, expression) PROPAGATE_FAIL_TV(auto, var, expression)
634
635/**
636 * If a function returns an FCanFail inside another function which may also return another error use this convenience
637 * macro to propagate the failure. This is only useful with expressions which doesn't return a value upon success.
638 */
639#define PROPAGATE_FAIL(expression) PROPAGATE_FAIL_V(PREPROCESSOR_JOIN(tempResult, __LINE__), expression)
#define MCRO_DEBUG_BREAK()
Definition Macros.h:33
FORCEINLINE int32 GetInnerErrorCount() const
Definition Error.h:147
virtual TSharedRef< SErrorDisplay > CreateErrorWidget()
void Initialize()
Definition Error.h:108
SelfRef< Self > WithError(this Self &&self, const FString &name, const TSharedRef< Error > &input, bool condition=true)
Definition Error.h:341
SelfRef< Self > WithMessage(this Self &&self, const FString &input, bool condition=true)
Definition Error.h:174
SelfRef< Self > WithMessageFC(this Self &&self, bool condition, const TCHAR *input, FormatArgs &&... fmtArgs)
Definition Error.h:205
FString ToString() const
SelfRef< Self > WithCodeContext(this Self &&self, const FString &input, bool condition=true)
Definition Error.h:308
SelfRef< Self > WithErrors(this Self &&self, const TSharedRef< Errors > &... errors)
Definition Error.h:373
SelfRef< Self > WithAppendixF(this Self &&self, const FString &name, const TCHAR *text, FormatArgs &&... fmtArgs)
Definition Error.h:418
FStringView GetSeverityString() const
SelfRef< Self > WithDetails(this Self &&self, const FString &input, bool condition=true)
Definition Error.h:260
SelfRef< Self > Notify(this Self &&self, Observable::IState< IErrorPtr > &state)
Definition Error.h:443
SelfRef< Self > WithError(this Self &&self, const TSharedRef< Error > &input, bool condition=true)
Definition Error.h:324
std::string ToStringUtf8() const
FString Details
Definition Error.h:70
virtual void SerializeYaml(YAML::Emitter &emitter, bool isRoot) const
SelfRef< Self > WithMessageF(this Self &&self, const TCHAR *input, FormatArgs &&... fmtArgs)
Definition Error.h:189
SelfRef< Self > WithSeverity(this Self &&self, EErrorSeverity input)
Definition Error.h:220
virtual void SerializeErrorPropagation(YAML::Emitter &emitter) const
FString GetErrorPropagationJoined() const
FORCEINLINE decltype(InnerErrors) ::TRangedForConstIterator end() const
Definition Error.h:101
void AddCppStackTrace(const FString &name, int32 numAdditionalStackFramesToIgnore, bool fastWalk)
FORCEINLINE FString const & GetCodeContext() const
Definition Error.h:145
FORCEINLINE decltype(InnerErrors) ::TRangedForConstIterator begin() const
Definition Error.h:99
SelfRef< Self > WithErrors(this Self &&self, bool condition, const TSharedRef< Errors > &... errors)
Definition Error.h:388
SelfRef< Self > AsFatal(this Self &&self)
Definition Error.h:236
FString CodeContext
Definition Error.h:71
FORCEINLINE FString const & GetMessage() const
Definition Error.h:143
TArray< std::source_location > ErrorPropagation
Definition Error.h:67
virtual void SerializeInnerErrors(YAML::Emitter &emitter) const
SelfRef< Self > AsRecoverable(this Self &&self)
Definition Error.h:228
SelfRef< Self > WithBlueprintStackTrace(this Self &&self, const FString &name={}, bool condition=true)
Definition Error.h:470
SelfRef< Self > WithAppendixFC(this Self &&self, bool condition, const FString &name, const TCHAR *text, FormatArgs &&... fmtArgs)
Definition Error.h:434
SelfRef< Self > WithDetailsF(this Self &&self, const TCHAR *input, FormatArgs &&... fmtArgs)
Definition Error.h:276
SelfRef< Self > BreakDebugger(this Self &&self)
Definition Error.h:451
FORCEINLINE FString const & GetDetails() const
Definition Error.h:144
FORCEINLINE decltype(InnerErrors) ::TRangedForIterator begin()
Definition Error.h:98
FORCEINLINE TMap< FString, IErrorRef > const & GetInnerErrors() const
Definition Error.h:146
FORCEINLINE decltype(InnerErrors) ::TRangedForIterator end()
Definition Error.h:100
SelfRef< Self > WithCppStackTrace(this Self &&self, const FString &name={}, bool condition=true, int32 numAdditionalStackFramesToIgnore=0, bool fastWalk=!UE_BUILD_DEBUG)
Definition Error.h:459
SelfRef< Self > WithAppendix(this Self &&self, const FString &name, const FString &text, bool condition=true)
Definition Error.h:403
SelfRef< Self > WithErrors(this Self &&self, const TArray< TTuple< FString, IErrorRef > > &input, bool condition=true)
Definition Error.h:355
FString Message
Definition Error.h:69
static TSharedRef< T > Make(T *newError, Args &&... args)
Definition Error.h:136
virtual void AddError(const FString &name, const TSharedRef< IError > &error, const FString &typeOverride={})
TMap< FString, IErrorRef > InnerErrors
Definition Error.h:66
virtual void SerializeMembers(YAML::Emitter &emitter, bool isRoot) const
SelfRef< Self > WithDetailsFC(this Self &&self, bool condition, const TCHAR *input, FormatArgs &&... fmtArgs)
Definition Error.h:293
SelfRef< Self > WithLocation(this Self &&self, std::source_location location=std::source_location::current())
Definition Error.h:488
SelfRef< Self > AsCrashing(this Self &&self)
Definition Error.h:244
FORCEINLINE int32 GetSeverityInt() const
Definition Error.h:142
FORCEINLINE EErrorSeverity GetSeverity() const
Definition Error.h:141
void AddBlueprintStackTrace(const FString &name)
TArray< FString > GetErrorPropagation() const
virtual void NotifyState(Observable::IState< IErrorPtr > &state)
virtual void AddAppendix(const FString &name, const FString &text, const FString &type=TEXT("Appendix"))
TSharedRef< std::decay_t< Self > > SelfRef
Definition Types.h:58
FORCEINLINE FCanFail Success()
Definition Error.h:590
TSharedPtr< IError > IErrorPtr
Definition Error.Fwd.h:26
TSharedRef< T, Mode > MakeShareableInit(T *newObject, Args &&... args)
MCRO_API FString DynamicPrintf(const TCHAR *fmt,...)
const FString TTypeString
Definition TypeName.h:146
Definition Void.h:25
TMaybe(From &&value)
Definition Error.h:541
TMaybe(TMaybe< From > const &other)
Definition Error.h:545
auto TryGetValue() const -> TOptional< T > const &
Definition Error.h:559
TMaybe(TSharedRef< ErrorType > const &error)
Definition Error.h:553
bool HasValue() const
Definition Error.h:555
auto GetValue() -> T &
Definition Error.h:561
TMaybe(TMaybe< From > &&other)
Definition Error.h:549
auto GetError() const -> IErrorPtr
Definition Error.h:564
bool HasError() const
Definition Error.h:556
TMaybe(From const &value)
Definition Error.h:537
auto TryGetValue() -> TOptional< T > &
Definition Error.h:558
auto GetValue() const -> T const &
Definition Error.h:562