feat: add more API methods to Result and Option
This commit is contained in:
181
src/ro.h
181
src/ro.h
@ -7,12 +7,20 @@
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
|
||||
#define None(T) (ro::Option<T>())
|
||||
#define Some(v) (ro::Option(v))
|
||||
#define None(...) ro::Option<__VA_ARGS__>()
|
||||
#define Some(...) ro::Option(__VA_ARGS__)
|
||||
#define ERR(fmt, ...) Error(ro::sfmt("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__))
|
||||
#define try_unwrap(l,...) try{l=(__VA_ARGS__).unwrap();}catch(ro::Error e){return e;}
|
||||
// #define Err(e) (ro::Result(e))
|
||||
// #define Ok(v) (ro::Result(v))
|
||||
#define try_unwrap(l, ...) \
|
||||
try \
|
||||
{ \
|
||||
l = (__VA_ARGS__).unwrap(); \
|
||||
} \
|
||||
catch (ro::Error e) \
|
||||
{ \
|
||||
return e; \
|
||||
}
|
||||
|
||||
#define ERR_INVALID_ACESS "Invalid access"
|
||||
|
||||
namespace ro
|
||||
{
|
||||
@ -42,13 +50,13 @@ namespace ro
|
||||
return std::string(l.what()) == std::string(r.what());
|
||||
}
|
||||
|
||||
friend inline Error operator+(const Error & l, const Error &r)
|
||||
friend inline Error operator+(const Error &l, const Error &r)
|
||||
{
|
||||
return Error(std::string(l.what()) + "\n" + r.what());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename E>
|
||||
template <typename T, typename E = ro::Error>
|
||||
class Result;
|
||||
|
||||
template <typename T>
|
||||
@ -56,6 +64,7 @@ namespace ro
|
||||
{
|
||||
|
||||
public:
|
||||
using type_t = T;
|
||||
Option(T obj) : m_some(obj), m_notnull(true){};
|
||||
Option() : m_notnull(false){};
|
||||
|
||||
@ -64,6 +73,7 @@ namespace ro
|
||||
insert(value);
|
||||
return *this;
|
||||
};
|
||||
|
||||
inline friend bool operator==(const Option<T> &l, const Option<T> &r)
|
||||
{
|
||||
if (!l.m_notnull && !r.m_notnull)
|
||||
@ -111,13 +121,43 @@ namespace ro
|
||||
|
||||
inline bool is_none() const { return !m_notnull; };
|
||||
inline bool is_some() const { return m_notnull; };
|
||||
|
||||
template <typename U>
|
||||
inline U match(const std::function<U(T &)> &expected, const std::function<U()> &unexpected)
|
||||
{
|
||||
if (is_some())
|
||||
{
|
||||
return expected(m_some);
|
||||
}
|
||||
return unexpected();
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
inline U match(const std::function<U(const T &)> &expected, const std::function<U()> &unexpected) const
|
||||
{
|
||||
if (is_some())
|
||||
{
|
||||
return expected(m_some);
|
||||
}
|
||||
return unexpected();
|
||||
}
|
||||
|
||||
inline const T &unwrap() const
|
||||
{
|
||||
if (m_notnull)
|
||||
{
|
||||
return m_some;
|
||||
}
|
||||
throw Error("Object is None");
|
||||
throw Error(ERR_INVALID_ACESS);
|
||||
}
|
||||
|
||||
inline T &unwrap()
|
||||
{
|
||||
if (m_notnull)
|
||||
{
|
||||
return m_some;
|
||||
}
|
||||
throw Error(ERR_INVALID_ACESS);
|
||||
}
|
||||
|
||||
inline const T &unwrap_or(const T &alt) const
|
||||
@ -138,7 +178,7 @@ namespace ro
|
||||
return fn();
|
||||
}
|
||||
|
||||
inline const T &get_or_insert(const T &value)
|
||||
inline T &get_or_insert(const T &value)
|
||||
{
|
||||
if (!m_notnull)
|
||||
{
|
||||
@ -146,7 +186,8 @@ namespace ro
|
||||
}
|
||||
return m_some;
|
||||
}
|
||||
inline const T &insert(const T &value)
|
||||
|
||||
inline T &insert(const T &value)
|
||||
{
|
||||
m_some = value;
|
||||
m_notnull = true;
|
||||
@ -184,7 +225,7 @@ namespace ro
|
||||
|
||||
inline bool into(T &output) const
|
||||
{
|
||||
if(is_some())
|
||||
if (is_some())
|
||||
{
|
||||
output = m_some;
|
||||
return true;
|
||||
@ -250,6 +291,62 @@ namespace ro
|
||||
return Option<std::tuple<T, U>>();
|
||||
}
|
||||
|
||||
template <typename U, typename R>
|
||||
inline Option<R> zip_with(const Option<U> &other, const std::function<R(const T &, const U &)> &fn)
|
||||
{
|
||||
if (m_notnull && other.is_some())
|
||||
{
|
||||
return fn(m_some, other.unwrap());
|
||||
}
|
||||
return Option<R>();
|
||||
}
|
||||
|
||||
template <typename Y, typename Z>
|
||||
inline typename std::enable_if<std::is_base_of<std::tuple<Y, Z>, T>::value, std::tuple<Option<Y>, Option<Z>>>::type unzip()
|
||||
{
|
||||
if (is_some())
|
||||
{
|
||||
return std::tuple<Option<Y>, Option<Z>>(Some(std::get<Y>(m_some)), Some(std::get<Z>(m_some)));
|
||||
}
|
||||
return std::tuple<Option<Y>, Option<Z>>(None(Y), None(Z));
|
||||
}
|
||||
|
||||
template <typename X = T>
|
||||
inline typename std::enable_if<std::is_base_of<Option<typename X::type_t>, X>::value, X>::type flatten()
|
||||
{
|
||||
if (is_some())
|
||||
{
|
||||
return m_some;
|
||||
}
|
||||
return None(typename X::type_t);
|
||||
}
|
||||
|
||||
template <typename X = T>
|
||||
inline typename std::enable_if<std::is_base_of<Result<typename X::type_ok_t, typename X::type_err_t>, X>::value, Result<Option<typename X::type_ok_t>, typename X::type_err_t>>::type transpose()
|
||||
{
|
||||
if (is_none())
|
||||
{
|
||||
return Option<typename X::type_ok_t>();
|
||||
}
|
||||
if (m_some.is_ok())
|
||||
{
|
||||
return m_some.ok();
|
||||
}
|
||||
return m_some.unwrap_err();
|
||||
}
|
||||
|
||||
inline Option<T> replace(const T &value)
|
||||
{
|
||||
|
||||
Option<T> ret;
|
||||
if (is_some())
|
||||
{
|
||||
ret = m_some;
|
||||
}
|
||||
insert(value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
T m_some;
|
||||
bool m_notnull;
|
||||
@ -260,6 +357,8 @@ namespace ro
|
||||
{
|
||||
|
||||
public:
|
||||
using type_ok_t = T;
|
||||
using type_err_t = E;
|
||||
Result(T obj) : m_result(obj){};
|
||||
Result(E err) { m_error.insert(err); };
|
||||
Result(){};
|
||||
@ -329,6 +428,26 @@ namespace ro
|
||||
inline bool is_ok() const { return m_error.is_none(); };
|
||||
inline bool is_err() const { return m_error.is_some(); };
|
||||
|
||||
template <typename U>
|
||||
inline U match(const std::function<U(T &)> &expected, const std::function<U(E &)> &unexpected)
|
||||
{
|
||||
if (is_ok())
|
||||
{
|
||||
return expected(m_result);
|
||||
}
|
||||
return unexpected(m_error.unwrap());
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
inline U match(const std::function<U(const T &)> &expected, const std::function<U(const E &)> &unexpected) const
|
||||
{
|
||||
if (is_ok())
|
||||
{
|
||||
return expected(m_result);
|
||||
}
|
||||
return unexpected(m_error.unwrap());
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
inline Result<T, F> or_else(const std::function<Result<T, F>(const E &)> &fn)
|
||||
{
|
||||
@ -338,7 +457,6 @@ namespace ro
|
||||
}
|
||||
return fn(m_error.unwrap());
|
||||
}
|
||||
|
||||
inline const T &unwrap() const
|
||||
{
|
||||
if (is_ok())
|
||||
@ -348,6 +466,15 @@ namespace ro
|
||||
throw m_error.unwrap();
|
||||
}
|
||||
|
||||
inline T &unwrap()
|
||||
{
|
||||
if (is_ok())
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
throw m_error.unwrap();
|
||||
}
|
||||
|
||||
inline const E &unwrap_err() const
|
||||
{
|
||||
if (is_err())
|
||||
@ -357,7 +484,7 @@ namespace ro
|
||||
throw m_result;
|
||||
}
|
||||
|
||||
inline const T &expect(const E& e) const
|
||||
inline const T &expect(const E &e) const
|
||||
{
|
||||
if (is_ok())
|
||||
{
|
||||
@ -417,7 +544,7 @@ namespace ro
|
||||
|
||||
inline bool into(T &output) const
|
||||
{
|
||||
if(is_ok())
|
||||
if (is_ok())
|
||||
{
|
||||
output = m_result;
|
||||
return true;
|
||||
@ -434,6 +561,32 @@ namespace ro
|
||||
return fn(m_error.unwrap());
|
||||
}
|
||||
|
||||
template <typename X = T>
|
||||
inline typename std::enable_if<std::is_base_of<Result<typename X::type_ok_t, typename X::type_err_t>, X>::value, X>::type flatten()
|
||||
{
|
||||
if (is_ok())
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
return m_error.unwrap();
|
||||
}
|
||||
|
||||
template <typename X = T>
|
||||
inline typename std::enable_if<std::is_base_of<Option<typename X::type_t>, X>::value, Option<Result<typename X::type_t, E>>>::type transpose()
|
||||
{
|
||||
if (is_err())
|
||||
{
|
||||
return Result<typename X::type_t, E>(m_error.unwrap());
|
||||
}
|
||||
|
||||
if (m_result.is_none())
|
||||
{
|
||||
return None(Result<typename X::type_t, E>);
|
||||
}
|
||||
|
||||
return Result<typename X::type_t, E>(m_result.unwrap());
|
||||
}
|
||||
|
||||
inline const Option<E> &err() const { return m_error; }
|
||||
inline Option<T> ok() const { return is_ok() ? Option<T>(m_result) : Option<T>(); }
|
||||
|
||||
|
Reference in New Issue
Block a user