syntastica_core/language_set/
union.rs

1use std::borrow::Cow;
2
3use syntastica_highlight::HighlightConfiguration;
4use tft::FileType;
5
6use crate::Result;
7
8use super::{LanguageSet, SupportedLanguage};
9
10/// A combination of two arbitrary [`LanguageSet`]s into one.
11///
12/// [`Union`] implements [`LanguageSet`] for a pair of any two [`LanguageSet`]s. This allows
13/// combining multiple sets. The `R` set acts as the fallback. If a language is requested, first
14/// the left set is queried for a match, and only if it fails to provide one the right set will be
15/// queried.
16///
17/// The accompanying language type is [`EitherLang`].
18#[derive(Default)]
19pub struct Union<L, R> {
20    left: L,
21    right: R,
22}
23
24/// Either one of two language types.
25///
26/// Used to represent a [`SupportedLanguage`] for the [`Union`] language set.
27#[derive(Debug, Hash, PartialEq, Eq)]
28pub enum EitherLang<L, R> {
29    /// A language of the left set.
30    Left(L),
31
32    /// A language of the right set.
33    Right(R),
34}
35
36impl<L, R> Union<L, R> {
37    /// Create a new [`Union`] set by combining `left` and `right`.
38    pub fn new(left: L, right: R) -> Self {
39        Self { left, right }
40    }
41
42    /// Get a reference to the left set.
43    pub fn left(&self) -> &L {
44        &self.left
45    }
46
47    /// Get a reference to the right set.
48    pub fn right(&self) -> &R {
49        &self.right
50    }
51}
52
53impl<'s, L, R> LanguageSet<'s> for Union<L, R>
54where
55    L: LanguageSet<'s>,
56    R: LanguageSet<'s>,
57{
58    type Language = EitherLang<L::Language, R::Language>;
59
60    fn get_language(&self, language: Self::Language) -> Result<&HighlightConfiguration> {
61        match language {
62            EitherLang::Left(lang) => self.left.get_language(lang),
63            EitherLang::Right(lang) => self.right.get_language(lang),
64        }
65    }
66}
67
68impl<L, R> From<L> for EitherLang<L, R> {
69    fn from(value: L) -> Self {
70        Self::Left(value)
71    }
72}
73
74impl<'set, L, R, S, T> SupportedLanguage<'set, Union<S, T>> for EitherLang<L, R>
75where
76    L: SupportedLanguage<'set, S>,
77    R: SupportedLanguage<'set, T>,
78{
79    fn name(&self) -> Cow<'_, str> {
80        match self {
81            EitherLang::Left(lang) => lang.name(),
82            EitherLang::Right(lang) => lang.name(),
83        }
84    }
85
86    fn for_name(name: impl AsRef<str>, set: &'set Union<S, T>) -> Result<Self> {
87        L::for_name(name.as_ref(), &set.left)
88            .map(Self::Left)
89            .or_else(|_| R::for_name(name, &set.right).map(Self::Right))
90    }
91
92    fn for_file_type(file_type: FileType, set: &'set Union<S, T>) -> Option<Self> {
93        L::for_file_type(file_type, &set.left)
94            .map(Self::Left)
95            .or_else(|| R::for_file_type(file_type, &set.right).map(Self::Right))
96    }
97
98    fn for_injection(name: impl AsRef<str>, set: &'set Union<S, T>) -> Option<Self> {
99        L::for_injection(name.as_ref(), &set.left)
100            .map(Self::Left)
101            .or_else(|| R::for_injection(name, &set.right).map(Self::Right))
102    }
103}