#[derive(Copy,Clone,PartialEq,Debug)]// and everything you want
struct Choice(u8); // as you wrote #[repr(u8)] here
impl Choice{
const A:u8=0,
const B:u8=1,
const C:u8=2,
}
// const list_of_variants: [A, C] // compiler error
if list_of_variants[1] == Choice::C {
// Choice::C was available
}
Since your program could not compile directly, I modify your code a little bit to:
/*
I want to provide a library that allows someone to define an enum
where the library would take the enum and, based on some criteria,
generate a `vec` of some of it's variants.
The end user could then loop over the `vec` and ask:
Do I have Choice::One?
Do I have Choice::Two?
And so on.
*/
#[repr(u16)]
enum Choice {
One,
Two,
Three,
Four,
}
type E=Choice;
/////////////////////////////////////////////
//
// Library from some "Codebase A"
//
/////////////////////////////////////////////
pub mod library {
use crate::E;
/// Given a list of all possible variants in `E`, return a subset of
/// some of its variants. To do that:
/// - `E` must be an enum defined with a `repr` attribute
/// of one of the unsigned int types
/// - `U` must be the same as the `repr`
/// - `LEN` must be the same size as `E`
fn propose_choices< const LEN: usize, U>(possible_choice_indices: &[U; LEN]) -> Vec<E> {
// The magic numbers are only for the Playground. In real
// life, another process would generate indices that
// are guaranteed to be valid for enum `E`
let random_choices = vec![0u16, 3, 2];
let mut choices: Vec<E> = Vec::new();
for i in random_choices {
choices.push(unsafe { std::mem::transmute(i) });
}
choices
}
pub struct VariantChooser<const LEN: usize, U> {
choice_storage: [U; LEN]
}
impl<const LEN: usize, U> VariantChooser<LEN, U> {
pub fn using(possible_choice_indices: [U; LEN]) -> Self {
Self {
choice_storage: possible_choice_indices
}
}
pub fn choose(&self, do_something: impl Fn(&Vec<E>)) {
let choices = propose_choices::<LEN, U>(&self.choice_storage);
do_something(&choices);
}
}
}
/////////////////////////////////////////////
//
// Everything below is in some "Codebase B"
//
/////////////////////////////////////////////
fn do_something(choices: &Vec<Choice>) {
for c in choices {
match c {
Choice::One => println!("One"),
Choice::Two => println!("Two"),
Choice::Three => println!("Three"),
Choice::Four => println!("Four"),
}
}
}
fn main() {
// I wish I could do:
// ```
// const choices = library::VariantChooser::using(Choice);
// choices.choose(do_something);
// ```
// But, that doesn't seem possible.
// The next best thing might be to create a macro and use like:
// const chooser = library::variant_chooser!(
// enum Choice {
// One,
// Two,
// Three,
// Four
// }
// )
// chooser.choose(do_something);
// Changes to the enum must be made here as well. It's not in
// a macro because I'm just trying to convey the idea.
const ChoiceIndices: [u16; 4] = [0, 1, 2, 3];
library::VariantChooser::using(ChoiceIndices).choose(do_something);
}
In this case, change enum to struct is simple
Just modify
#[repr(u16)]
enum Choice {
One,
Two,
Three,
Four,
}
to
#[derive(Clone,Copy,Debug,PartialEq,Eq)]
struct Choice(u16);
impl Choice {
const One:Choice=Choice(0);
const Two:Choice=Choice(1);
const Three:Choice=Choice(2);
const Four:Choice=Choice(3);
}
and add a catch_all arm to every match clause:
match *c {
Choice::One => println!("One"),
Choice::Two => println!("Two"),
Choice::Three => println!("Three"),
Choice::Four => println!("Four"),
_ => panic!("five"),
}