Skip to main content

wows_core/
recognized.rs

1use std::fmt;
2
3/// A value that was either successfully recognized as a known variant `T`,
4/// or is an unrecognized raw value `Raw`.
5///
6/// This is conceptually similar to `Result<T, Raw>`, but for cases where the
7/// "error" isn't really an error — it's just a value we don't have a typed
8/// representation for. The raw value is preserved so callers can inspect or
9/// display it.
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
13pub enum Recognized<T, Raw = String> {
14    Known(T),
15    Unknown(Raw),
16}
17
18impl<T: Copy, Raw: Copy> Copy for Recognized<T, Raw> {}
19
20impl<T, Raw> Recognized<T, Raw> {
21    pub fn known(&self) -> Option<&T> {
22        match self {
23            Recognized::Known(t) => Some(t),
24            Recognized::Unknown(_) => None,
25        }
26    }
27
28    pub fn into_known(self) -> Option<T> {
29        match self {
30            Recognized::Known(t) => Some(t),
31            Recognized::Unknown(_) => None,
32        }
33    }
34
35    pub fn unknown(&self) -> Option<&Raw> {
36        match self {
37            Recognized::Known(_) => None,
38            Recognized::Unknown(raw) => Some(raw),
39        }
40    }
41
42    pub fn into_unknown(self) -> Option<Raw> {
43        match self {
44            Recognized::Known(_) => None,
45            Recognized::Unknown(raw) => Some(raw),
46        }
47    }
48
49    pub fn is_known(&self) -> bool {
50        matches!(self, Recognized::Known(_))
51    }
52
53    pub fn is_unknown(&self) -> bool {
54        matches!(self, Recognized::Unknown(_))
55    }
56
57    pub fn unwrap(self) -> T
58    where
59        Raw: fmt::Debug,
60    {
61        match self {
62            Recognized::Known(t) => t,
63            Recognized::Unknown(raw) => {
64                panic!("called `Recognized::unwrap()` on an `Unknown` value: {raw:?}")
65            }
66        }
67    }
68
69    pub fn expect(self, msg: &str) -> T
70    where
71        Raw: fmt::Debug,
72    {
73        match self {
74            Recognized::Known(t) => t,
75            Recognized::Unknown(raw) => panic!("{msg}: {raw:?}"),
76        }
77    }
78
79    pub fn unwrap_or(self, default: T) -> T {
80        match self {
81            Recognized::Known(t) => t,
82            Recognized::Unknown(_) => default,
83        }
84    }
85
86    pub fn unwrap_or_else<F: FnOnce(Raw) -> T>(self, f: F) -> T {
87        match self {
88            Recognized::Known(t) => t,
89            Recognized::Unknown(raw) => f(raw),
90        }
91    }
92
93    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Recognized<U, Raw> {
94        match self {
95            Recognized::Known(t) => Recognized::Known(f(t)),
96            Recognized::Unknown(raw) => Recognized::Unknown(raw),
97        }
98    }
99
100    pub fn map_unknown<U, F: FnOnce(Raw) -> U>(self, f: F) -> Recognized<T, U> {
101        match self {
102            Recognized::Known(t) => Recognized::Known(t),
103            Recognized::Unknown(raw) => Recognized::Unknown(f(raw)),
104        }
105    }
106
107    pub fn and_then<U, F: FnOnce(T) -> Recognized<U, Raw>>(self, f: F) -> Recognized<U, Raw> {
108        match self {
109            Recognized::Known(t) => f(t),
110            Recognized::Unknown(raw) => Recognized::Unknown(raw),
111        }
112    }
113
114    pub fn as_ref(&self) -> Recognized<&T, &Raw> {
115        match self {
116            Recognized::Known(t) => Recognized::Known(t),
117            Recognized::Unknown(raw) => Recognized::Unknown(raw),
118        }
119    }
120}
121
122impl<T, Raw> From<T> for Recognized<T, Raw> {
123    fn from(value: T) -> Self {
124        Recognized::Known(value)
125    }
126}
127
128impl<T: fmt::Display, Raw: fmt::Display> fmt::Display for Recognized<T, Raw> {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        match self {
131            Recognized::Known(t) => t.fmt(f),
132            Recognized::Unknown(raw) => raw.fmt(f),
133        }
134    }
135}