necessist_core/framework/
union.rs

1use super::{Interface, ToImplementation};
2use crate::LightContext;
3use anyhow::Result;
4use std::marker::PhantomData;
5
6#[cfg(feature = "clap")]
7use clap::{ValueEnum, builder::PossibleValue};
8
9pub trait IntoEnumIterator: Sized {
10    type Iterator: Iterator<Item = Self>;
11
12    fn iter() -> Self::Iterator;
13}
14
15impl<T: strum::IntoEnumIterator> IntoEnumIterator for T {
16    type Iterator = <Self as strum::IntoEnumIterator>::Iterator;
17
18    fn iter() -> Self::Iterator {
19        <Self as strum::IntoEnumIterator>::iter()
20    }
21}
22
23#[derive(Debug, Clone, Copy, Eq, PartialEq)]
24pub enum Union<L, R> {
25    Left(L),
26    Right(R),
27}
28
29pub enum Iter<L, R, I, J>
30where
31    L: IntoEnumIterator<Iterator = I>,
32    R: IntoEnumIterator<Iterator = J>,
33{
34    Left(I, PhantomData<L>),
35    Right(J, PhantomData<R>),
36}
37
38impl<L, R, I, J> Iter<L, R, I, J>
39where
40    L: IntoEnumIterator<Iterator = I>,
41    R: IntoEnumIterator<Iterator = J>,
42{
43    fn new() -> Self {
44        Self::Left(L::iter(), PhantomData)
45    }
46}
47
48impl<L, R, I, J> Iterator for Iter<L, R, I, J>
49where
50    L: IntoEnumIterator<Iterator = I>,
51    R: IntoEnumIterator<Iterator = J>,
52    I: Iterator<Item = L>,
53    J: Iterator<Item = R>,
54{
55    type Item = Union<L, R>;
56
57    fn next(&mut self) -> Option<Self::Item> {
58        if let Self::Left(left, _) = self {
59            if let Some(framework) = left.next() {
60                return Some(Union::Left(framework));
61            }
62            *self = Self::Right(R::iter(), PhantomData);
63        }
64        if let Self::Right(right, _) = self {
65            right.next().map(Union::Right)
66        } else {
67            unreachable!()
68        }
69    }
70}
71
72impl<L, R, I, J> IntoEnumIterator for Union<L, R>
73where
74    L: IntoEnumIterator<Iterator = I>,
75    R: IntoEnumIterator<Iterator = J>,
76    I: Iterator<Item = L>,
77    J: Iterator<Item = R>,
78{
79    type Iterator = Iter<L, R, I, J>;
80
81    fn iter() -> Self::Iterator {
82        Iter::new()
83    }
84}
85
86impl<L, R> ToImplementation for Union<L, R>
87where
88    L: ToImplementation,
89    R: ToImplementation,
90{
91    fn to_implementation(&self, context: &LightContext) -> Result<Option<Box<dyn Interface>>> {
92        match self {
93            Self::Left(left) => left.to_implementation(context),
94            Self::Right(right) => right.to_implementation(context),
95        }
96    }
97}
98
99#[cfg(feature = "clap")]
100impl<L, R> ValueEnum for Union<L, R>
101where
102    L: Clone + ValueEnum,
103    R: Clone + ValueEnum,
104{
105    fn value_variants<'a>() -> &'a [Self] {
106        let mut names = L::value_variants()
107            .iter()
108            .filter_map(|left| {
109                left.to_possible_value()
110                    .map(|left| left.get_name().to_owned())
111            })
112            .collect::<Vec<_>>();
113        names.extend(R::value_variants().iter().filter_map(|right| {
114            right
115                .to_possible_value()
116                .map(|right| right.get_name().to_owned())
117        }));
118        names.sort();
119        Box::leak(
120            names
121                .iter()
122                .flat_map(|name| Self::from_str(name, false))
123                .collect::<Vec<_>>()
124                .into_boxed_slice(),
125        )
126    }
127
128    fn to_possible_value(&self) -> Option<PossibleValue> {
129        match self {
130            Self::Left(left) => left.to_possible_value(),
131            Self::Right(right) => right.to_possible_value(),
132        }
133    }
134
135    fn from_str(input: &str, ignore_case: bool) -> Result<Self, String> {
136        L::from_str(input, ignore_case)
137            .map(Self::Left)
138            .or_else(|left| {
139                R::from_str(input, ignore_case)
140                    .map(Self::Right)
141                    .map_err(|right| format!("{left}, {right}"))
142            })
143    }
144}