How to define a range of u8 that can exhaust in pattern match

This looks like a perfect use case for enum. Note that enum in Rust is not like it is in C. In C, enum is a narrow wrapper around an integer. In Rust, it's a full-fledged sum-of-product algebraic data type, capable of describing basically whatever you want.

#[derive(Clone, Copy)]
pub enum SlidingRole { King, Queen }

fn adf(role: SlidingRole) -> u8 {
  match role {
    SlidingRole::King => 3,
    SlidingRole::Queen => 2,
  }
}

Now SlidingRole is a new type with exactly two possible values. If you want, you can provide From / TryFrom instances for conversion to / from u8.

I also derive Clone and Copy so you don't have to worry about borrow semantics in the above example. For simple enums (where it's just a list of cases like yours is), this is fine. If your enum starts to contain something like a String, you won't be able to get Copy since it's no longer a plain memcpy to clone data. You'll probably want to add Eq, PartialEq, and potentially an ordering, depending on your specific use cases.

Finally, if you need the underlying representation to be u8 (for instance, if you're interfacing with a C library), you can use a repr annotation to force this.

#[repr(u8)]
#[derive(Clone, Copy)]
pub enum SlidingRole { King, Queen }

Now SlidingRole is genuinely still a new type, distinct from u8. But it's guaranteed to use a memory layout equivalent to u8, so you can pass it to C functions expecting a u8, and you can transmute it to/from a u8 safely. This is a niche and more advanced use case, so I don't recommend doing it unless you specifically need the data to be a u8.

In particular, you shouldn't do this for the purposes of premature optimization; Rust's compiler is already really good at optimizing datatypes, so "I think this fits best in u8" is not a good use case; the compiler is smarter than you or I when it comes to building assembly code. Stick with a plain enum unless you have a very niche use case.