Skip to main content

anno_eval/eval/
backend_name.rs

1//! Backend Name Enum
2//!
3//! Type-safe backend identifiers replacing string-based names.
4//!
5//! # Example
6//!
7//! ```rust
8//! use anno_eval::eval::backend_name::BackendName;
9//!
10//! let backend = BackendName::Stacked;
11//! let name: &str = backend.as_str();
12//! ```
13
14use serde::{Deserialize, Serialize};
15use std::fmt;
16
17/// Type-safe backend identifier.
18///
19/// Replaces string-based backend names with compile-time checked enum.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
21#[non_exhaustive]
22pub enum BackendName {
23    // Always available
24    /// Pattern-based NER using regular expressions.
25    Pattern,
26    /// Heuristic NER using capitalization and context rules.
27    Heuristic,
28    /// Stacked NER combining Pattern and Heuristic backends.
29    Stacked,
30
31    // ONNX backends
32    /// BERT-based NER via ONNX runtime.
33    #[cfg(feature = "onnx")]
34    BertOnnx,
35    /// GLiNER zero-shot NER via ONNX runtime.
36    #[cfg(feature = "onnx")]
37    GLiNEROnnx,
38    /// NuNER zero-shot NER via ONNX runtime.
39    #[cfg(feature = "onnx")]
40    NuNER,
41    /// W2NER word-word relation NER via ONNX runtime.
42    #[cfg(feature = "onnx")]
43    W2NER,
44    /// GLiNER v2 zero-shot NER via ONNX runtime.
45    #[cfg(feature = "onnx")]
46    GLiNERMultitask,
47    /// GLiNER with polynomial attention via ONNX runtime.
48    #[cfg(feature = "onnx")]
49    GLiNERPoly,
50    /// DeBERTa v3 NER via ONNX runtime.
51    #[cfg(feature = "onnx")]
52    DeBERTaV3,
53    /// ALBERT NER via ONNX runtime.
54    #[cfg(feature = "onnx")]
55    ALBERT,
56    /// TPLinker relation extraction via ONNX runtime.
57    #[cfg(feature = "onnx")]
58    TPLinker,
59
60    // Candle backends
61    /// Candle-based NER (pure Rust inference).
62    #[cfg(feature = "candle")]
63    CandleNER,
64    /// GLiNER via Candle (pure Rust inference).
65    #[cfg(feature = "candle")]
66    GLiNERCandle,
67    /// GLiNER v2 via Candle (pure Rust inference).
68    #[cfg(feature = "candle")]
69    GLiNERMultitaskCandle,
70
71    // Coreference
72    /// Coreference resolution backend.
73    CorefResolver,
74
75    // Universal
76    /// Universal NER supporting all entity types.
77    UniversalNER,
78}
79
80impl BackendName {
81    /// Get string representation of backend name.
82    ///
83    /// Returns the canonical string identifier for this backend.
84    #[must_use]
85    pub fn as_str(&self) -> &'static str {
86        match self {
87            BackendName::Pattern => "pattern",
88            BackendName::Heuristic => "heuristic",
89            BackendName::Stacked => "stacked",
90            #[cfg(feature = "onnx")]
91            BackendName::BertOnnx => "bert_onnx",
92            #[cfg(feature = "onnx")]
93            BackendName::GLiNEROnnx => "gliner_onnx",
94            #[cfg(feature = "onnx")]
95            BackendName::NuNER => "nuner",
96            #[cfg(feature = "onnx")]
97            BackendName::W2NER => "w2ner",
98            #[cfg(feature = "onnx")]
99            BackendName::GLiNERMultitask => "gliner_multitask",
100            #[cfg(feature = "onnx")]
101            BackendName::GLiNERPoly => "gliner_poly",
102            #[cfg(feature = "onnx")]
103            BackendName::DeBERTaV3 => "deberta_v3",
104            #[cfg(feature = "onnx")]
105            BackendName::ALBERT => "albert",
106            #[cfg(feature = "onnx")]
107            BackendName::TPLinker => "tplinker",
108            #[cfg(feature = "candle")]
109            BackendName::CandleNER => "candle_ner",
110            #[cfg(feature = "candle")]
111            BackendName::GLiNERCandle => "gliner_candle",
112            #[cfg(feature = "candle")]
113            BackendName::GLiNERMultitaskCandle => "gliner_multitask_candle",
114            BackendName::CorefResolver => "coref_resolver",
115            BackendName::UniversalNER => "universal_ner",
116        }
117    }
118
119    /// Parse backend name from string.
120    ///
121    /// Returns `None` if the string doesn't match any known backend.
122    #[must_use]
123    pub fn try_parse(s: &str) -> Option<Self> {
124        match s.to_lowercase().as_str() {
125            "pattern" | "patternner" | "regex" | "regexner" => Some(BackendName::Pattern),
126            "heuristic" | "heuristicner" => Some(BackendName::Heuristic),
127            "stacked" | "stackedner" => Some(BackendName::Stacked),
128            #[cfg(feature = "onnx")]
129            "bert_onnx" | "bertneronnx" => Some(BackendName::BertOnnx),
130            #[cfg(feature = "onnx")]
131            "gliner" => Some(BackendName::GLiNEROnnx),
132            #[cfg(feature = "onnx")]
133            "gliner_onnx" | "glineronnx" => Some(BackendName::GLiNEROnnx),
134            #[cfg(feature = "onnx")]
135            "nuner" | "nunerzero" => Some(BackendName::NuNER),
136            #[cfg(feature = "onnx")]
137            "w2ner" => Some(BackendName::W2NER),
138            #[cfg(feature = "onnx")]
139            "gliner_multitask" | "gliner_multitask_onnx" => Some(BackendName::GLiNERMultitask),
140            #[cfg(feature = "onnx")]
141            "gliner_poly" | "glinerpoly" => Some(BackendName::GLiNERPoly),
142            #[cfg(feature = "onnx")]
143            "deberta_v3" | "debertav3" => Some(BackendName::DeBERTaV3),
144            #[cfg(feature = "onnx")]
145            "albert" | "albert_ner" => Some(BackendName::ALBERT),
146            #[cfg(feature = "onnx")]
147            "tplinker" => Some(BackendName::TPLinker),
148            #[cfg(feature = "candle")]
149            "candle_ner" | "candlener" => Some(BackendName::CandleNER),
150            #[cfg(feature = "candle")]
151            "gliner_candle" | "glinercandle" => Some(BackendName::GLiNERCandle),
152            #[cfg(feature = "candle")]
153            "gliner_multitask_candle" => Some(BackendName::GLiNERMultitaskCandle),
154            "coref_resolver" | "corefresolver" | "simplecorefresolver" => {
155                Some(BackendName::CorefResolver)
156            }
157            "universal_ner" | "universal-ner" | "universalner" => Some(BackendName::UniversalNER),
158            _ => None,
159        }
160    }
161
162    /// Get all available backends (based on enabled features).
163    ///
164    /// Returns a vector of all `BackendName` variants that are available
165    /// given the current feature flags.
166    #[must_use]
167    pub fn all_available() -> Vec<Self> {
168        #[allow(unused_mut)] // mut needed when onnx/candle features enabled
169        let mut backends = vec![
170            BackendName::Pattern,
171            BackendName::Heuristic,
172            BackendName::Stacked,
173            BackendName::CorefResolver,
174            BackendName::UniversalNER,
175        ];
176
177        #[cfg(feature = "onnx")]
178        {
179            backends.extend(&[
180                BackendName::BertOnnx,
181                BackendName::GLiNEROnnx,
182                BackendName::NuNER,
183                BackendName::W2NER,
184                BackendName::GLiNERMultitask,
185                BackendName::GLiNERPoly,
186                BackendName::DeBERTaV3,
187                BackendName::ALBERT,
188                BackendName::TPLinker,
189            ]);
190        }
191
192        #[cfg(feature = "candle")]
193        {
194            backends.extend(&[BackendName::CandleNER, BackendName::GLiNERCandle]);
195        }
196
197        #[cfg(all(feature = "candle", feature = "onnx"))]
198        {
199            backends.push(BackendName::GLiNERMultitaskCandle);
200        }
201
202        backends
203    }
204}
205
206impl fmt::Display for BackendName {
207    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208        write!(f, "{}", self.as_str())
209    }
210}
211
212impl std::str::FromStr for BackendName {
213    type Err = String;
214
215    fn from_str(s: &str) -> Result<Self, Self::Err> {
216        Self::try_parse(s).ok_or_else(|| format!("Unknown backend: '{}'", s))
217    }
218}
219
220impl From<BackendName> for String {
221    fn from(name: BackendName) -> Self {
222        name.as_str().to_string()
223    }
224}