Skip to content

Commit

Permalink
add more things to readme
Browse files Browse the repository at this point in the history
  • Loading branch information
altalk23 committed Dec 3, 2024
1 parent d8bdda2 commit 16e30ab
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 7 deletions.
175 changes: 171 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,179 @@ The design of this library is heavily inspired by [rust's Result type](https://d

```cpp
Result<int> integerDivision(int a, int b) {
if (b == 0)
if (b == 0) {
return Err("Division by zero");
}
return Ok(a / b);
}

int value = integerDivision(3, 2).unwrap(); // 1
value = integerDivision(3, 0).unwrap(); // Throws a runtime error
value = integerDivision(3, 0).unwrapOr(0); // 0
int main() {
int value = integerDivision(3, 2).unwrapOrDefault();
assert(value == 1);

value = integerDivision(3, 0).unwrapOr(0);
assert(value == 0);
}
```
## Extracting the values
There are tons of conveniency tools to error check and extract the value from a Result. You are encouraged to use them.
### Returning early
Here are the convenience utils for returning early from a Result returning function:
```cpp
Result<int> myFunction() {
// !! Only on Clang
// Returns Err early from the function if the result is an error,
// otherwise passes the value
int p1 = GEODE_UNWRAP(integerDivision(3, 2));
assert(p1 == 1);
// You can use this macro on MSVC as well if you don't need the value
// it will return Err early if the result is an error
GEODE_UNWRAP(integerDivision(3, 2));
// Returns Err early from the function if the result is an error,
// otherwise sets the value into the variable
GEODE_UNWRAP_INTO(int p2, integerDivision(3, 2));
assert(p2 == 1);
return Ok(0);
}
```

### Entering into an if block
Here are the convenience utils for entering into an if block with the underlying value:
```cpp
int main() {
// Only enters the block if the result is ok,
// setting the value into the variable
if (GEODE_UNWRAP_IF_OK(p3, integerDivision(3, 2))) {
assert(p3 == 1);
}

// Only enters the block if the result is an error,
// setting the value into the variable
if (GEODE_UNWRAP_IF_ERR(e1, integerDivision(3, 0))) {
assert(e1 == "Division by zero");
}
}
```

### Setting the value inline
Here are the convenience utils for setting a value inline with manually handling the error:
```cpp
int main() {
// Enters the trailing block if the result is an error,
// otherwise sets the value into the variable
GEODE_UNWRAP_OR_ELSE(p4, integerDivision(3, 2)) {
return -1;
}
assert(p4 == 1);

GEODE_UNWRAP_OR_ELSE(p5, integerDivision(3, 0)) {
p5 = -1;
}
assert(p5 == -1);
}
```

### Builtin functions
And here are the functions built into the Result to extract the value:
```cpp
int main() {
// Returns the value if the result is ok,
// otherwise returns the default value for type
int p6 = integerDivision(3, 0).unwrapOrDefault();
assert(p6 == 0);

// Returns the value if the result is ok,
// otherwise returns the passed value
int p7 = integerDivision(3, 0).unwrapOr(-1);
assert(p7 == -1);

// Returns the value if the result is ok,
// otherwise returns the result of the operation
int p8 = integerDivision(3, 0).unwrapOrElse([](){
return -1;
});
assert(p7 == -1);

// NOT RECOMMENDED!!!
// Returns the value if the result is ok,
// otherwise **throws an exception**
int p9 = integerDivision(3, 2).unwrap();
std::string e2 = integerDivision(3, 0).unwrapErr();
}
```

## Manipulating the values
There are lots of ways to manipulate a Result to better fit the required use case. Feel free to use as you please.

### Chaining results
Here are the convenience utils for chaining results:
```cpp
int main() {
// Returns the passed result if the result is ok,
// otherwise returns the result of itself
int v1 = integerDivision(3, 2).and_(integerDivision(5, 2)).unwrapOrDefault();
assert(v1 == 2);

// Returns the passed result if the result is err,
// otherwise returns the result of itself
int v2 = integerDivision(3, 2).or_(integerDivision(5, 2)).unwrapOrDefault();
assert(v2 == 1);

// Returns the result of the operation if the result is ok,
// otherwise returns the result of itself
int v3 = integerDivision(3, 2).andThen([](){
return Ok(10);
}).unwrapOrDefault();
assert(v3 == 10);

// Returns the result of the operation if the result is err,
// otherwise returns the result of itself
int v4 = integerDivision(3, 0).orElse([](){
return Ok(-10);
}).unwrapOrDefault();
assert(v4 == 10);
}
```

### Mapping values
Here are the convenience utils for mapping values:
```cpp
int main() {
// Maps the value if the result is ok,
// otherwise returns the result of itself
if (GEODE_UNWRAP_IF_OK(v5, integerDivision(3, 2).map([](int v){
return v * 2;
}))) {
assert(v5 == 2);
}

// Maps the error if the result is err,
// otherwise returns the result of itself
if (GEODE_UNWRAP_IF_ERR(e1, integerDivision(3, 0).mapErr([](auto const& e){
return e + "!";
}))) {
assert(e1 == "Division by zero!");
}

// Maps the value if the result is ok,
// otherwise returns the result of the operation
int v6 = integerDivision(3, 2).mapOrElse([](){
return -1;
}, [](int v){
return v * 2;
});
assert(v6 == 2);

// Maps the value if the result is ok,
// otherwise returns the given value
int v7 = integerDivision(3, 2).mapOr(-1, [](int v){
return v * 2;
});
assert(v7 == 2);
}
```
4 changes: 2 additions & 2 deletions include/Geode/Result.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@
(variable = std::move(GEODE_CONCAT(res, __LINE__)).value(), true)
#endif

#if !defined(GEODE_UNWRAP_INTO_ELSE)
#define GEODE_UNWRAP_INTO_ELSE(variable, ...) \
#if !defined(GEODE_UNWRAP_OR_ELSE)
#define GEODE_UNWRAP_OR_ELSE(variable, ...) \
geode::impl::ResultOkType<decltype(__VA_ARGS__)> variable; \
auto GEODE_CONCAT(res, __LINE__) = __VA_ARGS__; \
if (GEODE_CONCAT(res, __LINE__).isOk()) \
Expand Down
2 changes: 1 addition & 1 deletion test/Misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ TEST_CASE("Misc") {
}

SECTION("Unwrap Into Else") {
GEODE_UNWRAP_INTO_ELSE(value, divideConstexpr(32, 2)) {
GEODE_UNWRAP_OR_ELSE(value, divideConstexpr(32, 2)) {
FAIL("Expected the block to not be executed");
}
REQUIRE(value == 16);
Expand Down

0 comments on commit 16e30ab

Please sign in to comment.