Skip to main content

rubo4e/generated/v202607/
geraetetyp.rs

1#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
2#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3#[cfg_attr(
4    feature = "strum",
5    derive(strum::EnumString, strum::EnumIter, strum::IntoStaticStr)
6)]
7#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
8#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
9/// Auflistung möglicher abzurechnender Gerätetypen.
10#[non_exhaustive]
11pub enum Geraetetyp {
12    #[cfg_attr(feature = "serde", serde(rename = "MULTIPLEXANLAGE"))]
13    #[cfg_attr(feature = "strum", strum(serialize = "MULTIPLEXANLAGE"))]
14    Multiplexanlage,
15    #[cfg_attr(feature = "serde", serde(rename = "PAUSCHALANLAGE"))]
16    #[cfg_attr(feature = "strum", strum(serialize = "PAUSCHALANLAGE"))]
17    Pauschalanlage,
18    #[cfg_attr(feature = "serde", serde(rename = "VERSTAERKERANLAGE"))]
19    #[cfg_attr(feature = "strum", strum(serialize = "VERSTAERKERANLAGE"))]
20    Verstaerkeranlage,
21    #[cfg_attr(feature = "serde", serde(rename = "SUMMATIONSGERAET"))]
22    #[cfg_attr(feature = "strum", strum(serialize = "SUMMATIONSGERAET"))]
23    Summationsgeraet,
24    #[cfg_attr(feature = "serde", serde(rename = "IMPULSGEBER"))]
25    #[cfg_attr(feature = "strum", strum(serialize = "IMPULSGEBER"))]
26    Impulsgeber,
27    #[cfg_attr(feature = "serde", serde(rename = "MENGENUMWERTER"))]
28    #[cfg_attr(feature = "strum", strum(serialize = "MENGENUMWERTER"))]
29    Mengenumwerter,
30    #[cfg_attr(feature = "serde", serde(rename = "STROMWANDLER"))]
31    #[cfg_attr(feature = "strum", strum(serialize = "STROMWANDLER"))]
32    Stromwandler,
33    #[cfg_attr(feature = "serde", serde(rename = "SPANNUNGSWANDLER"))]
34    #[cfg_attr(feature = "strum", strum(serialize = "SPANNUNGSWANDLER"))]
35    Spannungswandler,
36    #[cfg_attr(feature = "serde", serde(rename = "KOMBIMESSWANDLER"))]
37    #[cfg_attr(feature = "strum", strum(serialize = "KOMBIMESSWANDLER"))]
38    Kombimesswandler,
39    #[cfg_attr(feature = "serde", serde(rename = "BLOCKSTROMWANDLER"))]
40    #[cfg_attr(feature = "strum", strum(serialize = "BLOCKSTROMWANDLER"))]
41    Blockstromwandler,
42    #[cfg_attr(feature = "serde", serde(rename = "DATENLOGGER"))]
43    #[cfg_attr(feature = "strum", strum(serialize = "DATENLOGGER"))]
44    Datenlogger,
45    #[cfg_attr(feature = "serde", serde(rename = "KOMMUNIKATIONSANSCHLUSS"))]
46    #[cfg_attr(feature = "strum", strum(serialize = "KOMMUNIKATIONSANSCHLUSS"))]
47    Kommunikationsanschluss,
48    #[cfg_attr(feature = "serde", serde(rename = "MODEM"))]
49    #[cfg_attr(feature = "strum", strum(serialize = "MODEM"))]
50    Modem,
51    #[cfg_attr(feature = "serde", serde(rename = "TELEKOMMUNIKATIONSEINRICHTUNG"))]
52    #[cfg_attr(feature = "strum", strum(serialize = "TELEKOMMUNIKATIONSEINRICHTUNG"))]
53    Telekommunikationseinrichtung,
54    #[cfg_attr(feature = "serde", serde(rename = "MODERNE_MESSEINRICHTUNG"))]
55    #[cfg_attr(feature = "strum", strum(serialize = "MODERNE_MESSEINRICHTUNG"))]
56    ModerneMesseinrichtung,
57    ///
58    /// **Wire spelling:** `INTELLIGENTES_MESSYSTEM` (two `s`).  ⚠ BO4E spells the
59    /// *same* iMSys concept differently across BOs: `Zaehlertyp::IntelligentesMesssystem`
60    /// uses `INTELLIGENTES_MESSSYSTEM` (three `s`).  This divergence is upstream, not a
61    /// `rubo4e` transcription error; each BO keeps its own canonical spelling.
62    #[cfg_attr(feature = "serde", serde(rename = "INTELLIGENTES_MESSYSTEM"))]
63    #[cfg_attr(feature = "strum", strum(serialize = "INTELLIGENTES_MESSYSTEM"))]
64    IntelligentesMessystem,
65    #[cfg_attr(feature = "serde", serde(rename = "STEUEREINRICHTUNG"))]
66    #[cfg_attr(feature = "strum", strum(serialize = "STEUEREINRICHTUNG"))]
67    Steuereinrichtung,
68    #[cfg_attr(feature = "serde", serde(rename = "TARIFSCHALTGERAET"))]
69    #[cfg_attr(feature = "strum", strum(serialize = "TARIFSCHALTGERAET"))]
70    Tarifschaltgeraet,
71    #[cfg_attr(feature = "serde", serde(rename = "RUNDSTEUEREMPFAENGER"))]
72    #[cfg_attr(feature = "strum", strum(serialize = "RUNDSTEUEREMPFAENGER"))]
73    Rundsteuerempfaenger,
74    #[cfg_attr(feature = "serde", serde(rename = "OPTIONALE_ZUS_ZAEHLEINRICHTUNG"))]
75    #[cfg_attr(feature = "strum", strum(serialize = "OPTIONALE_ZUS_ZAEHLEINRICHTUNG"))]
76    OptionaleZusZaehleinrichtung,
77    #[cfg_attr(feature = "serde", serde(rename = "MESSWANDLERSATZ_IMS_MME"))]
78    #[cfg_attr(feature = "strum", strum(serialize = "MESSWANDLERSATZ_IMS_MME"))]
79    MesswandlersatzImsMme,
80    #[cfg_attr(feature = "serde", serde(rename = "KOMBIMESSWANDLER_IMS_MME"))]
81    #[cfg_attr(feature = "strum", strum(serialize = "KOMBIMESSWANDLER_IMS_MME"))]
82    KombimesswandlerImsMme,
83    #[cfg_attr(feature = "serde", serde(rename = "TARIFSCHALTGERAET_IMS_MME"))]
84    #[cfg_attr(feature = "strum", strum(serialize = "TARIFSCHALTGERAET_IMS_MME"))]
85    TarifschaltgeraetImsMme,
86    #[cfg_attr(feature = "serde", serde(rename = "RUNDSTEUEREMPFAENGER_IMS_MME"))]
87    #[cfg_attr(feature = "strum", strum(serialize = "RUNDSTEUEREMPFAENGER_IMS_MME"))]
88    RundsteuerempfaengerImsMme,
89    #[cfg_attr(feature = "serde", serde(rename = "TEMPERATUR_KOMPENSATION"))]
90    #[cfg_attr(feature = "strum", strum(serialize = "TEMPERATUR_KOMPENSATION"))]
91    TemperaturKompensation,
92    #[cfg_attr(feature = "serde", serde(rename = "HOECHSTBELASTUNGS_ANZEIGER"))]
93    #[cfg_attr(feature = "strum", strum(serialize = "HOECHSTBELASTUNGS_ANZEIGER"))]
94    HoechstbelastungsAnzeiger,
95    #[cfg_attr(feature = "serde", serde(rename = "SONSTIGES_GERAET"))]
96    #[cfg_attr(feature = "strum", strum(serialize = "SONSTIGES_GERAET"))]
97    SonstigesGeraet,
98    #[cfg_attr(feature = "serde", serde(rename = "EDL_21"))]
99    #[cfg_attr(feature = "strum", strum(serialize = "EDL_21"))]
100    Edl21,
101    #[cfg_attr(feature = "serde", serde(rename = "EDL_40_ZAEHLERAUFSATZ"))]
102    #[cfg_attr(feature = "strum", strum(serialize = "EDL_40_ZAEHLERAUFSATZ"))]
103    Edl40Zaehleraufsatz,
104    #[cfg_attr(feature = "serde", serde(rename = "EDL_40"))]
105    #[cfg_attr(feature = "strum", strum(serialize = "EDL_40"))]
106    Edl40,
107    #[cfg_attr(feature = "serde", serde(rename = "TELEFONANSCHLUSS"))]
108    #[cfg_attr(feature = "strum", strum(serialize = "TELEFONANSCHLUSS"))]
109    Telefonanschluss,
110    #[cfg_attr(feature = "serde", serde(rename = "MODEM_GSM"))]
111    #[cfg_attr(feature = "strum", strum(serialize = "MODEM_GSM"))]
112    ModemGsm,
113    #[cfg_attr(feature = "serde", serde(rename = "MODEM_GPRS"))]
114    #[cfg_attr(feature = "strum", strum(serialize = "MODEM_GPRS"))]
115    ModemGprs,
116    #[cfg_attr(feature = "serde", serde(rename = "MODEM_FUNK"))]
117    #[cfg_attr(feature = "strum", strum(serialize = "MODEM_FUNK"))]
118    ModemFunk,
119    #[cfg_attr(feature = "serde", serde(rename = "MODEM_GSM_O_LG"))]
120    #[cfg_attr(feature = "strum", strum(serialize = "MODEM_GSM_O_LG"))]
121    ModemGsmOLg,
122    #[cfg_attr(feature = "serde", serde(rename = "MODEM_GSM_M_LG"))]
123    #[cfg_attr(feature = "strum", strum(serialize = "MODEM_GSM_M_LG"))]
124    ModemGsmMLg,
125    #[cfg_attr(feature = "serde", serde(rename = "MODEM_FESTNETZ"))]
126    #[cfg_attr(feature = "strum", strum(serialize = "MODEM_FESTNETZ"))]
127    ModemFestnetz,
128    #[cfg_attr(feature = "serde", serde(rename = "MODEM_GPRS_M_LG"))]
129    #[cfg_attr(feature = "strum", strum(serialize = "MODEM_GPRS_M_LG"))]
130    ModemGprsMLg,
131    #[cfg_attr(feature = "serde", serde(rename = "PLC_KOM"))]
132    #[cfg_attr(feature = "strum", strum(serialize = "PLC_KOM"))]
133    PlcKom,
134    #[cfg_attr(feature = "serde", serde(rename = "ETHERNET_KOM"))]
135    #[cfg_attr(feature = "strum", strum(serialize = "ETHERNET_KOM"))]
136    EthernetKom,
137    #[cfg_attr(feature = "serde", serde(rename = "DSL_KOM"))]
138    #[cfg_attr(feature = "strum", strum(serialize = "DSL_KOM"))]
139    DslKom,
140    #[cfg_attr(feature = "serde", serde(rename = "LTE_KOM"))]
141    #[cfg_attr(feature = "strum", strum(serialize = "LTE_KOM"))]
142    LteKom,
143    #[cfg_attr(feature = "serde", serde(rename = "KOMPAKT_MU"))]
144    #[cfg_attr(feature = "strum", strum(serialize = "KOMPAKT_MU"))]
145    KompaktMu,
146    #[cfg_attr(feature = "serde", serde(rename = "SYSTEM_MU"))]
147    #[cfg_attr(feature = "strum", strum(serialize = "SYSTEM_MU"))]
148    SystemMu,
149    #[cfg_attr(feature = "serde", serde(rename = "TEMPERATUR_MU"))]
150    #[cfg_attr(feature = "strum", strum(serialize = "TEMPERATUR_MU"))]
151    TemperaturMu,
152    #[cfg_attr(feature = "serde", serde(rename = "ZUSTANDS_MU"))]
153    #[cfg_attr(feature = "strum", strum(serialize = "ZUSTANDS_MU"))]
154    ZustandsMu,
155    /// Unknown or future variant — produced when deserializing a value
156    /// that is not yet known to this version of the library.
157    #[cfg_attr(feature = "serde", serde(other, rename = "UNKNOWN"))]
158    #[cfg_attr(feature = "strum", strum(serialize = "UNKNOWN"))]
159    Unknown,
160}
161impl Geraetetyp {
162    /// All variants defined by the BO4E schema, in declaration order.
163    ///
164    /// Excludes the forward-compatibility [`Geraetetyp::Unknown`] catch-all, so this
165    /// is exactly the set of values that appear on the wire.  Available **without**
166    /// the `strum` feature — use it to drift-guard SQL `CHECK` lists and mappings.
167    pub const VARIANTS: &'static [Self] = &[
168        Self::Multiplexanlage,
169        Self::Pauschalanlage,
170        Self::Verstaerkeranlage,
171        Self::Summationsgeraet,
172        Self::Impulsgeber,
173        Self::Mengenumwerter,
174        Self::Stromwandler,
175        Self::Spannungswandler,
176        Self::Kombimesswandler,
177        Self::Blockstromwandler,
178        Self::Datenlogger,
179        Self::Kommunikationsanschluss,
180        Self::Modem,
181        Self::Telekommunikationseinrichtung,
182        Self::ModerneMesseinrichtung,
183        Self::IntelligentesMessystem,
184        Self::Steuereinrichtung,
185        Self::Tarifschaltgeraet,
186        Self::Rundsteuerempfaenger,
187        Self::OptionaleZusZaehleinrichtung,
188        Self::MesswandlersatzImsMme,
189        Self::KombimesswandlerImsMme,
190        Self::TarifschaltgeraetImsMme,
191        Self::RundsteuerempfaengerImsMme,
192        Self::TemperaturKompensation,
193        Self::HoechstbelastungsAnzeiger,
194        Self::SonstigesGeraet,
195        Self::Edl21,
196        Self::Edl40Zaehleraufsatz,
197        Self::Edl40,
198        Self::Telefonanschluss,
199        Self::ModemGsm,
200        Self::ModemGprs,
201        Self::ModemFunk,
202        Self::ModemGsmOLg,
203        Self::ModemGsmMLg,
204        Self::ModemFestnetz,
205        Self::ModemGprsMLg,
206        Self::PlcKom,
207        Self::EthernetKom,
208        Self::DslKom,
209        Self::LteKom,
210        Self::KompaktMu,
211        Self::SystemMu,
212        Self::TemperaturMu,
213        Self::ZustandsMu,
214    ];
215    /// Number of schema-defined variants (equal to `VARIANTS.len()`), excluding the
216    /// [`Geraetetyp::Unknown`] catch-all.  Stable for this schema version.
217    pub const COUNT: usize = Self::VARIANTS.len();
218    /// Returns an iterator over all **known** variants of `Geraetetyp`.
219    ///
220    /// Yields only variants that correspond to values defined in the BO4E schema
221    /// (i.e. [`Self::VARIANTS`]), never the [`Geraetetyp::Unknown`] catch-all.
222    /// Available **without** the `strum` feature.
223    ///
224    /// # Example
225    /// ```
226    /// # use rubo4e::current::Geraetetyp;
227    /// // Never yields the `Unknown` catch-all, so the count matches `COUNT`.
228    /// assert_eq!(Geraetetyp::iter_known().count(), Geraetetyp::COUNT);
229    /// assert!(Geraetetyp::iter_known().all(|v| v.is_known()));
230    /// ```
231    pub fn iter_known() -> impl Iterator<Item = Self> + Clone {
232        Self::VARIANTS.iter().copied()
233    }
234    /// Returns the canonical BO4E wire string (SCREAMING_SNAKE_CASE) for this value.
235    ///
236    /// [`Geraetetyp::Unknown`] renders as `"UNKNOWN"`, matching its serialized form.
237    pub const fn as_wire(&self) -> &'static str {
238        match self {
239            Self::Multiplexanlage => "MULTIPLEXANLAGE",
240            Self::Pauschalanlage => "PAUSCHALANLAGE",
241            Self::Verstaerkeranlage => "VERSTAERKERANLAGE",
242            Self::Summationsgeraet => "SUMMATIONSGERAET",
243            Self::Impulsgeber => "IMPULSGEBER",
244            Self::Mengenumwerter => "MENGENUMWERTER",
245            Self::Stromwandler => "STROMWANDLER",
246            Self::Spannungswandler => "SPANNUNGSWANDLER",
247            Self::Kombimesswandler => "KOMBIMESSWANDLER",
248            Self::Blockstromwandler => "BLOCKSTROMWANDLER",
249            Self::Datenlogger => "DATENLOGGER",
250            Self::Kommunikationsanschluss => "KOMMUNIKATIONSANSCHLUSS",
251            Self::Modem => "MODEM",
252            Self::Telekommunikationseinrichtung => "TELEKOMMUNIKATIONSEINRICHTUNG",
253            Self::ModerneMesseinrichtung => "MODERNE_MESSEINRICHTUNG",
254            Self::IntelligentesMessystem => "INTELLIGENTES_MESSYSTEM",
255            Self::Steuereinrichtung => "STEUEREINRICHTUNG",
256            Self::Tarifschaltgeraet => "TARIFSCHALTGERAET",
257            Self::Rundsteuerempfaenger => "RUNDSTEUEREMPFAENGER",
258            Self::OptionaleZusZaehleinrichtung => "OPTIONALE_ZUS_ZAEHLEINRICHTUNG",
259            Self::MesswandlersatzImsMme => "MESSWANDLERSATZ_IMS_MME",
260            Self::KombimesswandlerImsMme => "KOMBIMESSWANDLER_IMS_MME",
261            Self::TarifschaltgeraetImsMme => "TARIFSCHALTGERAET_IMS_MME",
262            Self::RundsteuerempfaengerImsMme => "RUNDSTEUEREMPFAENGER_IMS_MME",
263            Self::TemperaturKompensation => "TEMPERATUR_KOMPENSATION",
264            Self::HoechstbelastungsAnzeiger => "HOECHSTBELASTUNGS_ANZEIGER",
265            Self::SonstigesGeraet => "SONSTIGES_GERAET",
266            Self::Edl21 => "EDL_21",
267            Self::Edl40Zaehleraufsatz => "EDL_40_ZAEHLERAUFSATZ",
268            Self::Edl40 => "EDL_40",
269            Self::Telefonanschluss => "TELEFONANSCHLUSS",
270            Self::ModemGsm => "MODEM_GSM",
271            Self::ModemGprs => "MODEM_GPRS",
272            Self::ModemFunk => "MODEM_FUNK",
273            Self::ModemGsmOLg => "MODEM_GSM_O_LG",
274            Self::ModemGsmMLg => "MODEM_GSM_M_LG",
275            Self::ModemFestnetz => "MODEM_FESTNETZ",
276            Self::ModemGprsMLg => "MODEM_GPRS_M_LG",
277            Self::PlcKom => "PLC_KOM",
278            Self::EthernetKom => "ETHERNET_KOM",
279            Self::DslKom => "DSL_KOM",
280            Self::LteKom => "LTE_KOM",
281            Self::KompaktMu => "KOMPAKT_MU",
282            Self::SystemMu => "SYSTEM_MU",
283            Self::TemperaturMu => "TEMPERATUR_MU",
284            Self::ZustandsMu => "ZUSTANDS_MU",
285            Self::Unknown => "UNKNOWN",
286        }
287    }
288    /// **Strictly** parses a BO4E wire string into a known variant.
289    ///
290    /// Unlike the lenient `serde` / [`FromStr`](std::str::FromStr) path — which maps
291    /// any unrecognized value (a typo, a legacy code, or a value from a newer schema)
292    /// to [`Geraetetyp::Unknown`] — this returns
293    /// [`Err`](crate::error::UnknownVariant) for values not defined in this schema
294    /// version, including the literal `"UNKNOWN"`.  Use it at the ingest boundary to
295    /// reject bad values instead of silently degrading them.
296    ///
297    /// # Example
298    /// ```
299    /// # use rubo4e::current::Geraetetyp;
300    /// assert_eq!(Geraetetyp::from_wire("MULTIPLEXANLAGE"), Ok(Geraetetyp::Multiplexanlage));
301    /// // Out-of-schema values are rejected rather than degraded:
302    /// assert!(Geraetetyp::from_wire("NOT_A_REAL_VALUE").is_err());
303    /// // …including the `Unknown` catch-all's own wire spelling:
304    /// assert!(Geraetetyp::from_wire("UNKNOWN").is_err());
305    /// ```
306    pub fn from_wire(s: &str) -> Result<Self, crate::error::UnknownVariant> {
307        match s {
308            "MULTIPLEXANLAGE" => Ok(Self::Multiplexanlage),
309            "PAUSCHALANLAGE" => Ok(Self::Pauschalanlage),
310            "VERSTAERKERANLAGE" => Ok(Self::Verstaerkeranlage),
311            "SUMMATIONSGERAET" => Ok(Self::Summationsgeraet),
312            "IMPULSGEBER" => Ok(Self::Impulsgeber),
313            "MENGENUMWERTER" => Ok(Self::Mengenumwerter),
314            "STROMWANDLER" => Ok(Self::Stromwandler),
315            "SPANNUNGSWANDLER" => Ok(Self::Spannungswandler),
316            "KOMBIMESSWANDLER" => Ok(Self::Kombimesswandler),
317            "BLOCKSTROMWANDLER" => Ok(Self::Blockstromwandler),
318            "DATENLOGGER" => Ok(Self::Datenlogger),
319            "KOMMUNIKATIONSANSCHLUSS" => Ok(Self::Kommunikationsanschluss),
320            "MODEM" => Ok(Self::Modem),
321            "TELEKOMMUNIKATIONSEINRICHTUNG" => Ok(Self::Telekommunikationseinrichtung),
322            "MODERNE_MESSEINRICHTUNG" => Ok(Self::ModerneMesseinrichtung),
323            "INTELLIGENTES_MESSYSTEM" => Ok(Self::IntelligentesMessystem),
324            "STEUEREINRICHTUNG" => Ok(Self::Steuereinrichtung),
325            "TARIFSCHALTGERAET" => Ok(Self::Tarifschaltgeraet),
326            "RUNDSTEUEREMPFAENGER" => Ok(Self::Rundsteuerempfaenger),
327            "OPTIONALE_ZUS_ZAEHLEINRICHTUNG" => Ok(Self::OptionaleZusZaehleinrichtung),
328            "MESSWANDLERSATZ_IMS_MME" => Ok(Self::MesswandlersatzImsMme),
329            "KOMBIMESSWANDLER_IMS_MME" => Ok(Self::KombimesswandlerImsMme),
330            "TARIFSCHALTGERAET_IMS_MME" => Ok(Self::TarifschaltgeraetImsMme),
331            "RUNDSTEUEREMPFAENGER_IMS_MME" => Ok(Self::RundsteuerempfaengerImsMme),
332            "TEMPERATUR_KOMPENSATION" => Ok(Self::TemperaturKompensation),
333            "HOECHSTBELASTUNGS_ANZEIGER" => Ok(Self::HoechstbelastungsAnzeiger),
334            "SONSTIGES_GERAET" => Ok(Self::SonstigesGeraet),
335            "EDL_21" => Ok(Self::Edl21),
336            "EDL_40_ZAEHLERAUFSATZ" => Ok(Self::Edl40Zaehleraufsatz),
337            "EDL_40" => Ok(Self::Edl40),
338            "TELEFONANSCHLUSS" => Ok(Self::Telefonanschluss),
339            "MODEM_GSM" => Ok(Self::ModemGsm),
340            "MODEM_GPRS" => Ok(Self::ModemGprs),
341            "MODEM_FUNK" => Ok(Self::ModemFunk),
342            "MODEM_GSM_O_LG" => Ok(Self::ModemGsmOLg),
343            "MODEM_GSM_M_LG" => Ok(Self::ModemGsmMLg),
344            "MODEM_FESTNETZ" => Ok(Self::ModemFestnetz),
345            "MODEM_GPRS_M_LG" => Ok(Self::ModemGprsMLg),
346            "PLC_KOM" => Ok(Self::PlcKom),
347            "ETHERNET_KOM" => Ok(Self::EthernetKom),
348            "DSL_KOM" => Ok(Self::DslKom),
349            "LTE_KOM" => Ok(Self::LteKom),
350            "KOMPAKT_MU" => Ok(Self::KompaktMu),
351            "SYSTEM_MU" => Ok(Self::SystemMu),
352            "TEMPERATUR_MU" => Ok(Self::TemperaturMu),
353            "ZUSTANDS_MU" => Ok(Self::ZustandsMu),
354            other => Err(crate::error::UnknownVariant::new(other)),
355        }
356    }
357    /// Returns `true` if this value is the forward-compatibility
358    /// [`Geraetetyp::Unknown`] catch-all (an out-of-schema value).
359    pub const fn is_unknown(&self) -> bool {
360        matches!(self, Self::Unknown)
361    }
362    /// Returns `true` if this value is a known, schema-defined variant.
363    pub const fn is_known(&self) -> bool {
364        !self.is_unknown()
365    }
366}
367impl std::fmt::Display for Geraetetyp {
368    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
369        f.write_str(self.as_wire())
370    }
371}
372impl AsRef<str> for Geraetetyp {
373    fn as_ref(&self) -> &str {
374        self.as_wire()
375    }
376}
377#[cfg(feature = "versioned")]
378impl crate::bo4e_enum_sealed::Sealed for Geraetetyp {}
379#[cfg(feature = "versioned")]
380impl crate::Bo4eEnum for Geraetetyp {
381    const VARIANTS: &'static [Self] = Self::VARIANTS;
382    const COUNT: usize = Self::COUNT;
383    fn as_wire(&self) -> &'static str {
384        Self::as_wire(self)
385    }
386    fn from_wire(s: &str) -> Result<Self, crate::error::UnknownVariant> {
387        Self::from_wire(s)
388    }
389    fn is_unknown(&self) -> bool {
390        Self::is_unknown(self)
391    }
392}
393#[cfg(feature = "versioned")]
394impl crate::Bo4eStrict for Geraetetyp {
395    fn collect_unknown_enums(&self, path: &str, out: &mut Vec<String>) {
396        if self.is_unknown() {
397            out.push(path.to_owned());
398        }
399    }
400}
401#[cfg(feature = "sqlx")]
402impl sqlx::Type<sqlx::Postgres> for Geraetetyp {
403    fn type_info() -> sqlx::postgres::PgTypeInfo {
404        <String as sqlx::Type<sqlx::Postgres>>::type_info()
405    }
406}
407/// Encodes as the canonical BO4E wire string, borrowed from `as_wire` — no
408/// intermediate `String` or `serde_json::Value` is allocated.
409#[cfg(feature = "sqlx")]
410impl<'q> sqlx::Encode<'q, sqlx::Postgres> for Geraetetyp {
411    fn encode_by_ref(
412        &self,
413        buf: &mut <sqlx::Postgres as sqlx::Database>::ArgumentBuffer<'q>,
414    ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
415        let s: &str = self.as_wire();
416        <&str as sqlx::Encode<'q, sqlx::Postgres>>::encode_by_ref(&s, buf)
417    }
418}
419/// Decodes leniently, matching the `serde` path: a value the schema does not
420/// define becomes [`Geraetetyp::Unknown`] rather than a decode error, so a
421/// database row written by a newer schema version still reads back.
422///
423/// Use [`Geraetetyp::from_wire`] on a `String` column, or check
424/// [`Geraetetyp::is_known`], where out-of-schema values must be rejected.
425#[cfg(feature = "sqlx")]
426impl<'r> sqlx::Decode<'r, sqlx::Postgres> for Geraetetyp {
427    fn decode(
428        value: <sqlx::Postgres as sqlx::Database>::ValueRef<'r>,
429    ) -> Result<Self, sqlx::error::BoxDynError> {
430        let s = <&str as sqlx::Decode<sqlx::Postgres>>::decode(value)?;
431        Ok(Self::from_wire(s).unwrap_or(Self::Unknown))
432    }
433}
434/// Lets `Vec<Geraetetyp>` bind to a `TEXT[]` column.  Only this crate can
435/// provide it: the trait and the enum are both foreign to any consumer, so the
436/// orphan rule rules out a downstream impl.
437#[cfg(feature = "sqlx")]
438impl sqlx::postgres::PgHasArrayType for Geraetetyp {
439    fn array_type_info() -> sqlx::postgres::PgTypeInfo {
440        <String as sqlx::postgres::PgHasArrayType>::array_type_info()
441    }
442}
443#[cfg(test)]
444impl proptest::arbitrary::Arbitrary for Geraetetyp {
445    type Parameters = ();
446    type Strategy = proptest::strategy::BoxedStrategy<Self>;
447    fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
448        use proptest::prelude::*;
449        proptest::sample::select(Self::VARIANTS.to_vec()).boxed()
450    }
451}