If/Else and Pattern Matching
Garble supports two forms of conditional control flow, if/else and pattern matching, which are both expressions and always return a value. Here's an example of if/else:
pub fn main(x: i32) -> i32 {
if x < 0 {
-1
} else if x == 0 {
0
} else {
1
}
}
Here is an example of pattern matching on numbers:
pub fn main(x: i32) -> i32 {
match x {
0 => 1,
x => x,
}
}
Pattern matching is also supported for enums, structs, tuples and range literals (but not for arbitrary arrays), see the description of data types for more details. Here's how to match on an enum:
pub fn main(op: Op) -> OpResult {
match op {
Op::Zero => OpResult::Ok(0),
Op::Div(x, 0) => OpResult::DivByZero,
Op::Div(x, y) => OpResult::Ok(x / y),
}
}
As in Rust, patterns can be nested:
fn main(x: (bool, (u8, u8))) -> i32 {
match x {
(false, _) => 0,
(_, (_, 0)) => 1,
(_, (x, y)) => (x as i32) + (y as i32) + 1,
}
}
Garble also supports inclusive-end ranges in patterns (but only in patterns, not as array literals), using ..=
instead of ..
:
pub fn main(x: u8) -> u8 {
match x {
0..10 => 1,
10 => 2,
11 => 2,
13 => 2,
12..100 => 2,
100..=255 => 3,
}
}
Garble supports Rust's ..
shorthand in structs, to ignore all remaining fields:
struct FooBar {
foo: i32,
bar: i32,
}
pub fn main(x: (i32, i32)) -> i32 {
let (foo, bar) = x;
let foobar = FooBar { foo, bar };
match foobar {
FooBar { foo: 0, .. } => 1,
FooBar { foo, .. } => foo,
}
}
If patterns are not exhaustive, Garble will report the missing cases:
$ garble run garble_examples/error_examples/non_exhaustive_patterns.garble.rs --function=main '(true, (0, 0))'
Type error on line 2:5.
The patterns are not exhaustive. Missing cases:
(true, (1u8..=255u8, 1u8..=255u8))
...in expression:
| pub fn main(x: (bool, (u8, u8))) -> i32 {
2 > | match x {
> | ^^^^^^^^^
3 > | (false, _) => 0,
> | ^^^^^^^^^^^^^^^^^^^^^^^^
4 > | (_, (_, 0)) => 1,
> | ^^^^^^^^^^^^^^^^^^^^^^^^^
5 > | (_, (0, y)) => 2,
> | ^^^^^^^^^^^^^^^^^^^^^^^^^
6 > | }
> | ^^^^^
| }