summaryrefslogtreecommitdiff
path: root/AK
diff options
context:
space:
mode:
authorRobin Burchell <robin+git@viroteck.net>2019-07-30 15:31:24 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-07-31 09:06:39 +0200
commit7dd25141cdd0c5ce1bc0ccd3c2d9a3c470b63aaf (patch)
tree691eabd8c09ad4deaae47b6bacaa990261c25002 /AK
parent28362fcc57835bffc91f66585e17b25890509da9 (diff)
downloadserenity-7dd25141cdd0c5ce1bc0ccd3c2d9a3c470b63aaf.zip
Add Error<>
Put simply, Error<> is a way of forcing error handling onto an API user. Given a function like: bool might_work(); The following code might have been written previously: might_work(); // but what if it didn't? The easy way to work around this is of course to [[nodiscard]] might_work. But this doesn't work for more complex cases like, for instance, a hypothetical read() function which might return one of _many_ errors (typically signalled with an int, let's say). int might_read(); In such a case, the result is often _read_, but not properly handled. Like: return buffer.substr(0, might_read()); // but what if might_read returned an error? This is where Error<> comes in: typedef Error<int, 0> ReadError; ReadError might_read(); auto res = might_read(); if (might_read.failed()) { switch (res.value()) { case EBADF: ... } } Error<> uses clang's consumable attributes to force failed() to be checked on an Error instance. If it's not checked, then you get smacked.
Diffstat (limited to 'AK')
-rw-r--r--AK/Error.h53
1 files changed, 53 insertions, 0 deletions
diff --git a/AK/Error.h b/AK/Error.h
new file mode 100644
index 0000000000..b91721920d
--- /dev/null
+++ b/AK/Error.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <AK/Platform.h>
+
+namespace AK {
+
+template <typename T, auto NoErrorValue>
+class CONSUMABLE(unknown) Error {
+public:
+ RETURN_TYPESTATE(unknown)
+ Error()
+ : t(NoErrorValue)
+ {}
+
+ RETURN_TYPESTATE(unknown)
+ Error(T t)
+ : t(t)
+ {}
+
+ RETURN_TYPESTATE(unknown)
+ Error(Error&& other)
+ : t(move(other.t))
+ {
+ }
+
+ RETURN_TYPESTATE(unknown)
+ Error(const Error& other)
+ : t(other.t)
+ {
+ }
+
+ CALLABLE_WHEN("unknown", "consumed")
+ ~Error() {}
+
+ SET_TYPESTATE(consumed)
+ bool failed() const {
+ return t != NoErrorValue;
+ }
+
+ [[deprecated]]
+ SET_TYPESTATE(consumed)
+ void ignore() {}
+
+ const T& value() const { return t; }
+
+ bool operator==(const Error& o) { return t == o.t; }
+ bool operator!=(const Error& o) { return t != o.t; }
+ T t;
+};
+
+}
+
+using AK::Error;