14#include "CoreMinimal.h"
15#include "Templates/ValueOrError.h"
27#include "yaml-cpp/yaml.h"
30#include <source_location>
76 mutable bool bIsRoot =
false;
85 virtual void AddError(
const FString& name,
const TSharedRef<IError>& error,
const FString& typeOverride = {});
88 virtual void AddAppendix(
const FString& name,
const FString& text,
const FString& type =
TEXT_"Appendix");
90 void AddCppStackTrace(
const FString& name, int32 numAdditionalStackFramesToIgnore,
bool fastWalk);
104 FORCEINLINE
decltype(InnerErrors)::TRangedForIterator
begin() {
return InnerErrors.begin(); }
105 FORCEINLINE
decltype(InnerErrors)::TRangedForConstIterator
begin()
const {
return InnerErrors.begin(); }
106 FORCEINLINE
decltype(InnerErrors)::TRangedForIterator
end() {
return InnerErrors.end(); }
107 FORCEINLINE
decltype(InnerErrors)::TRangedForConstIterator
end()
const {
return InnerErrors.end(); }
126 friend auto operator << (YAML::Emitter& emitter,
IErrorRef const& error) -> YAML::Emitter&;
146 template <
CError T,
typename... Args>
147 requires CSharedInitializeable<T, Args...>
148 static TSharedRef<T>
Make(T* newError, Args&&... args)
163 FORCEINLINE int32
GetSeverityInt()
const {
return static_cast<int32
>(Severity); }
164 FORCEINLINE FString
const&
GetMessage()
const {
return Message; }
165 FORCEINLINE FString
const&
GetDetails()
const {
return Details; }
167 FORCEINLINE TMap<FString, IErrorRef>
const&
GetInnerErrors()
const {
return InnerErrors; }
195 template <
typename Self>
198 if (condition) self.Message = input;
199 return self.SharedThis(&self);
210 template <
typename Self, CStringFormatArgument... FormatArgs>
214 return self.SharedThis(&self);
226 template <
typename Self,
typename... FormatArgs>
230 return self.SharedThis(&self);
241 template <
typename Self>
244 self.Severity = input;
245 return self.SharedThis(&self);
249 template <
typename Self>
252 self.Severity = EErrorSeverity::Recoverable;
253 return self.SharedThis(&self);
257 template <
typename Self>
260 self.Severity = EErrorSeverity::Fatal;
261 return self.SharedThis(&self);
265 template <
typename Self>
268 self.Severity = EErrorSeverity::Crashing;
269 return self.SharedThis(&self);
283 template <
typename Self>
286 if (condition) self.Details = input;
287 return self.SharedThis(&self);
301 template <
typename Self, CStringFormatArgument... FormatArgs>
305 return self.SharedThis(&self);
320 template <
typename Self, CStringFormatArgument... FormatArgs>
324 return self.SharedThis(&self);
335 template <
typename Self>
338 if (condition) self.CodeContext = input;
339 return self.SharedThis(&self);
351 template <
typename Self, CError Error>
354 if (condition) self.AddError({}, input);
355 return self.SharedThis(&self);
368 template <
typename Self, CError Error>
371 if (condition) self.AddError(name, input);
372 return self.SharedThis(&self);
382 template <
typename Self>
387 for (
const auto& error : input)
388 self.AddError(error.Key, error.Value);
390 return self.SharedThis(&self);
400 template <
typename Self,
CError... Errors>
403 (self.AddError({}, errors), ...);
404 return self.SharedThis(&self);
415 template <
typename Self,
CError... Errors>
418 if (condition) self.WithErrors(errors...);
419 return self.SharedThis(&self);
430 template <
typename Self>
433 if (condition) self.AddAppendix(name, text);
434 return self.SharedThis(&self);
445 template <
typename Self, CStringFormatArgument... FormatArgs>
449 return self.SharedThis(&self);
461 template <
typename Self, CStringFormatArgument... FormatArgs>
466 return self.SharedThis(&self);
470 template <
typename Self>
473 self.NotifyState(state);
474 return self.SharedThis(&self);
478 template <
typename Self>
482 return self.SharedThis(&self);
486 template <
typename Self>
487 SelfRef<Self> WithCppStackTrace(
this Self&& self,
const FString& name = {},
bool condition =
true, int32 numAdditionalStackFramesToIgnore = 0,
bool fastWalk = !UE_BUILD_DEBUG)
489#if !UE_BUILD_SHIPPING
491 self.AddCppStackTrace(name, numAdditionalStackFramesToIgnore + 1, fastWalk);
493 return self.SharedThis(&self);
497 template <
typename Self>
500#if !UE_BUILD_SHIPPING
502 self.AddBlueprintStackTrace(name);
504 return self.SharedThis(&self);
517 template <
typename Self>
520 self.ErrorPropagation.Add(location);
521 return self.SharedThis(&self);
535 template <
typename Self>
539 OnErrorReported().Broadcast(self.SharedThis(&self));
541 return self.SharedThis(&self);
557 CFunctionCompatible_ArgumentsDecay<void(SelfRef<Self>)> Function
561 auto sharedSelf = self.SharedThis(&self);
562 function(sharedSelf);
588 template <CNonVo
id T>
598 template <
typename = T>
599 requires (!CDefaultInitializable<T>)
602 TEXT_"TMaybe has been default initialized, but a Value of {0} cannot be default initialized",
608 template <CDefaultInitializable = T>
612 template <CConvertibleToDecayed<T> From, CCopyConstructible = T>
613 TMaybe(From
const& value) : Value(value) {}
616 template <CConvertibleToDecayed<T> From, CMoveConstructible = T>
620 template <CConvertibleToDecayed<T> From, CCopyConstructible = T>
624 template <CConvertibleToDecayed<T> From, CMoveConstructible = T>
628 template <CError ErrorType>
629 TMaybe(TSharedRef<ErrorType>
const& error) : Error(error) {}
638 auto GetValue() const -> T const& {
return Value.GetValue(); }
655 template <
typename Self, CFunctionCompatible_ArgumentsDecay<
void(IErrorRef)> Function>
658 if (self.HasError()) mod(self.GetErrorRef());
662 operator TValueOrError<T, IErrorPtr>()
const
665 return MakeValue(Value.GetValue());
666 return MakeError(Error);
688#define MCRO_ERROR_LOG_3(categoryName, verbosity, error) \
689 UE_LOG(categoryName, verbosity, TEXT_"%s", *((error) \
695#define MCRO_ERROR_LOG_2(categoryName, verbosity) \
697 ->AsOperandWith([](IErrorRef const& error) \
699 UE_LOG(categoryName, verbosity, TEXT_"%s", *(error->ToString())); \
710#define ERROR_LOG(...) MACRO_OVERLOAD(MCRO_ERROR_LOG_, __VA_ARGS__)
712#define ERROR_CLOG(condition, categoryName, verbosity, error) \
713 UE_CLOG(condition, categoryName, verbosity, TEXT_"%s", *((error) \
719#define MCRO_ASSERT_RETURN_2(condition, error) \
720 if (UNLIKELY(!(condition))) \
721 return Mcro::Error::IError::Make(new error) \
724 ->WithCodeContext(PREPROCESSOR_TO_TEXT(condition))
726#define MCRO_ASSERT_RETURN_1(condition) MCRO_ASSERT_RETURN_2(condition, Mcro::Error::FAssertion())
735#define ASSERT_RETURN(...) MACRO_OVERLOAD(MCRO_ASSERT_RETURN_, __VA_ARGS__)
737#define MCRO_UNAVAILABLE_1(error) \
738 return Mcro::Error::IError::Make(new DEFAULT_ON_EMPTY(error, Mcro::Error::FUnavailable())) \
749#define UNAVAILABLE(error) MCRO_UNAVAILABLE_1(error)
751#define MCRO_PROPAGATE_FAIL_3(type, var, expression) \
752 type var = (expression); \
753 if (UNLIKELY(var.HasError())) return var.GetError() \
756#define MCRO_PROPAGATE_FAIL_2(var, expression) MCRO_PROPAGATE_FAIL_3(auto, var, expression)
757#define MCRO_PROPAGATE_FAIL_1(expression) MCRO_PROPAGATE_FAIL_2(PREPROCESSOR_JOIN(tempResult, __LINE__), expression)
772#define PROPAGATE_FAIL(...) MACRO_OVERLOAD(MCRO_PROPAGATE_FAIL_, __VA_ARGS__)
This header exists because STL headers in Android doesn't define STL concepts (other than same_as whi...
Use this header and Start.h in tandem to include third-party library headers which may not tolerate U...
#define FWD(...)
Shorten forwarding expression with this macro so one may not need to specify explicit type.
Use this header and End.h in tandem to include third-party library headers which may not tolerate Unr...
Use leading TEXT_ without parenthesis for Unreal compatible text literals.
#define TEXT_
A convenience alternative to Unreal's own TEXT macro but this one doesn't require parenthesis around ...
These two are the most useful types in the arsenal of the C++ developer. Use these for dummy types or...
"Extension" of a common TMulticastDelegate. It allows to define optional "flags" when adding a bindin...
A simple error type for checking booleans. It adds no extra features to IError.
A simple error type denoting that whatever is being accessed is not available like attempting to acce...
A base class for a structured error handling and reporting with modular architecture and fluent API.
virtual void SerializeYaml(YAML::Emitter &emitter) const
Override this function to change the method how this error is entirely serialized into a YAML format.
FORCEINLINE int32 GetInnerErrorCount() const
virtual TSharedRef< SErrorDisplay > CreateErrorWidget()
Override this function to customize how an error is displaxed for the end-user.
void Initialize()
This is an empty function so any IError can fulfill CSharedInitializeable without needing extra atten...
SelfRef< Self > WithError(this Self &&self, const FString &name, const TSharedRef< Error > &input, bool condition=true)
Add one inner error with specific name.
SelfRef< Self > WithMessage(this Self &&self, const FString &input, bool condition=true)
Specify error message with a fluent API.
SelfRef< Self > WithMessageFC(this Self &&self, bool condition, const TCHAR *input, FormatArgs &&... fmtArgs)
Specify formatted error message with a fluent API.
FString ToString() const
Render this error as a string using the YAML representation.
SelfRef< Self > WithCodeContext(this Self &&self, const FString &input, bool condition=true)
If available write a source code context into the error directly displaying where this error has occu...
SelfRef< Self > WithErrors(this Self &&self, const TSharedRef< Errors > &... errors)
Add multiple errors at once.
SelfRef< Self > WithAppendixF(this Self &&self, const FString &name, const TCHAR *text, FormatArgs &&... fmtArgs)
Add an extra plain text block inside inner errors.
FStringView GetSeverityString() const
Get the error severity as an unreal string.
SelfRef< Self > WithDetails(this Self &&self, const FString &input, bool condition=true)
Specify details for the error which may provide further context for the user or provide them reminder...
SelfRef< Self > Notify(this Self &&self, Observable::IState< IErrorPtr > &state)
Notify an observable state about this error.
SelfRef< Self > WithError(this Self &&self, const TSharedRef< Error > &input, bool condition=true)
Add a uniquely typed inner error.
std::string ToStringUtf8() const
Render this error as a std::string using the YAML representation.
SelfRef< Self > WithMessageF(this Self &&self, const TCHAR *input, FormatArgs &&... fmtArgs)
Specify formatted error message with a fluent API.
SelfRef< Self > WithSeverity(this Self &&self, EErrorSeverity input)
Specify severity with a fluent API.
virtual void SerializeErrorPropagation(YAML::Emitter &emitter) const
Override this method if error propagation history needs custom way of serialization.
FString GetErrorPropagationJoined() const
Same as GetErrorPropagation but items are separated by new line.
FORCEINLINE decltype(InnerErrors) ::TRangedForConstIterator end() const
void AddCppStackTrace(const FString &name, int32 numAdditionalStackFramesToIgnore, bool fastWalk)
FORCEINLINE FString const & GetCodeContext() const
virtual void AddAppendix(const FString &name, const FString &text, const FString &type=TEXT_"Appendix")
Add extra separate blocks of text in an ad-hoc fashion.
FORCEINLINE decltype(InnerErrors) ::TRangedForConstIterator begin() const
SelfRef< Self > AsOperandWith(this Self &&self, Function &&function)
Call an arbitrary function with this error. Other than cases like invoking macros inline operating on...
SelfRef< Self > WithErrors(this Self &&self, bool condition, const TSharedRef< Errors > &... errors)
Add multiple errors at once.
SelfRef< Self > AsFatal(this Self &&self)
Fatal shorthand.
virtual void SerializeMembers(YAML::Emitter &emitter) const
Override this method if direct members should be serialized differently or extra members are added by...
SelfRef< Self > Report(this Self &&self, bool condition=true)
Report this error to the global IError::OnErrorReported event once it is deemed "ready",...
FORCEINLINE FString const & GetMessage() const
TArray< std::source_location > ErrorPropagation
virtual void SerializeInnerErrors(YAML::Emitter &emitter) const
Override this method if inner errors needs custom way of serialization.
static auto OnErrorReported() -> TEventDelegate< void(IErrorRef)> &
When Report is called on an error this event is triggered, allowing issue tracking systems to react o...
SelfRef< Self > AsRecoverable(this Self &&self)
Recoverable shorthand.
SelfRef< Self > WithBlueprintStackTrace(this Self &&self, const FString &name={}, bool condition=true)
Shorthand for adding the current Blueprint stacktrace to this error.
SelfRef< Self > WithAppendixFC(this Self &&self, bool condition, const FString &name, const TCHAR *text, FormatArgs &&... fmtArgs)
Add an extra plain text block inside inner errors.
SelfRef< Self > WithDetailsF(this Self &&self, const TCHAR *input, FormatArgs &&... fmtArgs)
Specify formatted details for the error which may provide further context for the user or provide the...
SelfRef< Self > BreakDebugger(this Self &&self)
Break if a debugger is attached when this error is created.
FORCEINLINE FString const & GetDetails() const
FORCEINLINE decltype(InnerErrors) ::TRangedForIterator begin()
FORCEINLINE TMap< FString, IErrorRef > const & GetInnerErrors() const
FORCEINLINE decltype(InnerErrors) ::TRangedForIterator end()
SelfRef< Self > WithLocation(this Self &&self, std::source_location const &location=std::source_location::current())
Allow the error to record the source locations it has been handled at compile time....
SelfRef< Self > WithCppStackTrace(this Self &&self, const FString &name={}, bool condition=true, int32 numAdditionalStackFramesToIgnore=0, bool fastWalk=!UE_BUILD_DEBUG)
Shorthand for adding the current C++ stacktrace to this error.
SelfRef< Self > WithAppendix(this Self &&self, const FString &name, const FString &text, bool condition=true)
Add an extra plain text block inside inner errors.
SelfRef< Self > WithErrors(this Self &&self, const TArray< TTuple< FString, IErrorRef > > &input, bool condition=true)
Add multiple errors at once with optional names.
static TSharedRef< T > Make(T *newError, Args &&... args)
To ensure automatic type reflection use IError::Make instead of manually constructing error objects.
virtual void AddError(const FString &name, const TSharedRef< IError > &error, const FString &typeOverride={})
Override this method if inner errors added to current one needs special attention.
TMap< FString, IErrorRef > InnerErrors
SelfRef< Self > WithDetailsFC(this Self &&self, bool condition, const TCHAR *input, FormatArgs &&... fmtArgs)
Specify formatted details for the error which may provide further context for the user or provide the...
SelfRef< Self > AsCrashing(this Self &&self)
Crashing shorthand.
FORCEINLINE int32 GetSeverityInt() const
FORCEINLINE EErrorSeverity GetSeverity() const
void AddBlueprintStackTrace(const FString &name)
TArray< FString > GetErrorPropagation() const
Get a list of source locations where this error has been handled. This is not equivalent of stack-tra...
virtual void NotifyState(Observable::IState< IErrorPtr > &state)
Shorthand for combination of IHaveType and TSharedFromThis
TSharedRef< std::decay_t< Self > > SelfRef
Concept constraining input type argument T to an IError.
Contains utilities for structured error handling.
TSharedRef< IError > IErrorRef
Convenience alias for an instance of an error.
FORCEINLINE FCanFail Success()
Return an FCanFail or FTrueOrReason indicating a success or truthy output.
TSharedPtr< IError > IErrorPtr
Convenience alias for an instance of an error.
EErrorSeverity
Indicate the severity of an error and at what discretion the caller may treat it.
Utilities for TSharedPtr/Ref and related.
TSharedRef< T, Mode > MakeShareableInit(T *newObject, Args &&... args)
A wrapper around MakeShareable that automatically calls an initializer method Initialize on the insta...
Mixed text utilities and type traits.
FStringFormatOrderedArguments OrderedArguments(Args &&... args)
Create an ordered argument list for a string format from input arguments.
constexpr FStringView TTypeName
Get a friendly string of an input type without using typeid(T).name().
C++ native static reflection utilities, not to be confused with reflection of UObjects.
This struct may be used for situations where something needs to be returned but it's not meaningful t...
A TValueOrError alternative for IError which allows implicit conversion from values and errors (no ne...
TMaybe(From &&value)
Enable move constructor for T only when T is move constructable.
TMaybe(TMaybe< From > const &other)
Enable copy constructor for TMaybe only when T is copy constructable.
TMaybe()
Default initializing a TMaybe while its value is not default initializable, initializes the resulting...
auto TryGetValue() const -> TOptional< T > const &
TMaybe(TSharedRef< ErrorType > const &error)
Set this TMaybe to an erroneous state.
auto GetErrorRef() const -> IErrorRef
TMaybe()
If T is default initializable then the default state of TMaybe will be the default value of T,...
TMaybe(TMaybe< From > &&other)
Enable move constructor for TMaybe only when T is move constructable.
Self && ModifyError(this Self &&self, Function &&mod)
Modify a potential error stored in this monad.
auto GetError() const -> IErrorPtr
TMaybe(From const &value)
Enable copy constructor for T only when T is copy constructable.
auto TryGetValue() -> TOptional< T > &
auto GetValue() const -> T const &
Public API and base class for TState which shouldn't concern with policy flags or thread safety.