Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/coyorkdow/result
rust style error handling for cpp
https://github.com/coyorkdow/result
algebraic-data-types cpp error-handling functional-programming monad pattern-matching rust
Last synced: 7 days ago
JSON representation
rust style error handling for cpp
- Host: GitHub
- URL: https://github.com/coyorkdow/result
- Owner: coyorkdow
- License: mit
- Created: 2023-08-26T16:12:21.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2023-08-28T15:51:31.000Z (about 1 year ago)
- Last Synced: 2024-01-26T09:19:32.270Z (10 months ago)
- Topics: algebraic-data-types, cpp, error-handling, functional-programming, monad, pattern-matching, rust
- Language: C++
- Homepage:
- Size: 21.5 KB
- Stars: 4
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# result
Rust style error handling for cpp. It provides `result::Result` which supports pattern matching error handling and monadic operation.cpp17 required
## Basic Usage
```cpp
#include
#include#include "result.hpp"
using result::Result;// define a Result of int64, which error type is int
Result Multiply(int64_t a, int64_t b) {
int64_t res = a * b;
if (a != 0 && res / a != b) {
return {result::Err{}, -1}; // return error
}
return res; // return result
}int main() {
// do pattern matching
auto v = Multiply(1000, 1000).match(
result::Ok() = [](int64_t v) { return v; },
result::Err() = [](int err) { std::cerr << "arithmetic overflow\n"; return err; }
);
std::cout << v << '\n';
v = Multiply(std::numeric_limits::max(), 1000).match(
result::Ok() = [](int64_t v) { return v; },
result::Err() = [](int err) { std::cerr << "arithmetic overflow\n"; return err; }
);
std::cout << v << '\n';
}
```the return type of `result::Result::match` can be automatically deduced through the return type of the pattern handler.
The output will be
```
1000000
arithmetic overflow
-1
```## Using result::Error
`result::Error` is an type that designed to receive any type of the error. By using pattern matching it's easy to determine what kind of error that exactly is.
First, let's define a function template that returns `Result`
```cpp
template
Result ElementaryArithmeticFromZeroToMillion(char op, T x, T y) {
const T million = 1'000'000;
if (!(x >= 0 && x <= million) || !(y >= 0 && y <= million)) {
return {result::Err{}, result::OutOfRangeError{}};
}
using res_t = Result;
T res{};
switch (op) {
case '+':
res = x + y;
return (res >= 0 && res <= million) ? res_t{res} : res_t{result::Err{}, result::RangeError{}};
case '-':
res = x - y;
return (res >= 0 && res <= million) ? res_t{res} : res_t{result::Err{}, result::RangeError{}};
case '*':
res = x * y;
return (res >= 0 && res <= million) ? res_t{res} : res_t{result::Err{}, result::RangeError{}};
case '/':
if (y == 0) {
return {result::Err{}, result::DivideByZeroError{}};
}
res = x / y;
return (res >= 0 && res <= million) ? res_t{res} : res_t{result::Err{}, result::RangeError{}};
default:
return {result::Err{}, result::InvalidArgumentError{}};
}
}
``````cpp
auto v1 = ElementaryArithmeticFromZeroToMillion('+', 4, 3).match(
result::Ok() = [](int v) { return v; },
result::Err() = [](result::Error&&) { return 0; });
std::cout << v1 << '\n'; // 7auto v2 = ElementaryArithmeticFromZeroToMillion('-', 1.5, 10.5).match(
result::Ok() = [](double v) { return v; },
result::Err() =
[](result::OutOfRangeError) {
std::cout << "the arguments of calculating v2 out of range\n";
return -1;
},
result::Err() = /* match here */
[](result::RangeError) {
std::cout << "the result of calculating v2 out of range\n";
return -2;
},
result::Err() = /* the default error pattern. must be contained otherwise compile error */
[](result::Error&&) {
std::cout << "unknown error\n";
return -3;
});
std::cout << v2 << '\n'; // -2
````result::Error` itself also supports pattern matching.
```cpp
auto res = ElementaryArithmeticFromZeroToMillion('^', 1, 0);
res.error().match(
[](result::OutOfRangeError) {
std::cout << "the arguments out of range\n";
return 0;
},
[](result::InvalidArgumentError) { /* match here */
std::cout << "the arguments are invalid\n";
return 0;
},
[](result::Error) {
std::cout << "unknown error\n";
return 0;
});
```## Monadic operation
```cpp
auto res = ElementaryArithmeticFromZeroToMillion('^', 1, 0);
auto v3 = res.or_else([](const result::Error&) {
std::cout << "op ^ failed, change to op /\n";
return ElementaryArithmeticFromZeroToMillion('/', 1, 0);
})
.and_then([](int v) {
std::cout << "op / succeed\n";
return Result{v};
})
.or_else([](const result::Error&) {
std::cout << "op / failed, change to op +\n";
return ElementaryArithmeticFromZeroToMillion('+', 1, 0);
})
.and_then([](int v) {
std::cout << "op + succeed, time the result by 10\n";
return ElementaryArithmeticFromZeroToMillion('*', v, 10);
})
.or_else([](const result::Error&) {
std::cout << "eventually failed, set value as -1\n";
return Result{-1};
})
.value();
std::cout << "the final reuslt is " << v3 << '\n';
```The output will be
```
op ^ failed, change to op /
op / failed, change to op +
op + succeed, time the result by 10
the final reuslt is 10
```