1use std::{convert::Infallible, fmt, ops::Deref, str::FromStr};
2
3pub trait JsonLdValidate {
4 type Invalid;
5}
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10#[cfg_attr(feature = "serde", serde(untagged))]
11pub enum JsonLdLenient<T: JsonLdValidate> {
12 Valid(T),
13 Invalid(T::Invalid),
14}
15
16impl<T: JsonLdValidate> JsonLdLenient<T> {
17 pub fn new(value: &str) -> (Self, Option<T::Err>)
18 where
19 T: FromStr,
20 T::Invalid: From<String>,
21 {
22 match T::from_str(value) {
23 Ok(t) => (Self::Valid(t), None),
24 Err(e) => (Self::Invalid(T::Invalid::from(value.to_owned())), Some(e)),
25 }
26 }
27
28 pub fn from_string(value: String) -> (Self, Option<T::Err>)
29 where
30 T: FromStr,
31 T::Invalid: From<String>,
32 {
33 match T::from_str(&value) {
34 Ok(t) => (Self::Valid(t), None),
35 Err(e) => (Self::Invalid(T::Invalid::from(value)), Some(e)),
36 }
37 }
38
39 #[inline(always)]
44 pub fn is_valid(&self) -> bool {
45 matches!(self, Self::Valid(_))
46 }
47
48 pub fn is_valid_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
49 match self {
50 Self::Valid(t) => f(t),
51 Self::Invalid(_) => false,
52 }
53 }
54
55 pub fn as_valid(&self) -> Option<&T> {
56 match self {
57 Self::Valid(t) => Some(t),
58 Self::Invalid(_) => None,
59 }
60 }
61
62 pub fn into_valid(self) -> Result<T, T::Invalid> {
63 match self {
64 Self::Valid(t) => Ok(t),
65 Self::Invalid(e) => Err(e),
66 }
67 }
68
69 pub fn is_invalid(&self) -> bool {
70 matches!(self, Self::Invalid(_))
71 }
72
73 pub fn as_invalid(&self) -> Option<&T::Invalid> {
74 match self {
75 Self::Valid(_) => None,
76 Self::Invalid(t) => Some(t),
77 }
78 }
79
80 pub fn as_deref<'a>(&'a self) -> JsonLdLenient<&'a T::Target>
81 where
82 T: Deref,
83 T::Invalid: Deref,
84 &'a T::Target: JsonLdValidate<Invalid = &'a <T::Invalid as Deref>::Target>,
85 {
86 match self {
87 Self::Valid(t) => JsonLdLenient::Valid(t),
88 Self::Invalid(s) => JsonLdLenient::Invalid(s.deref()),
89 }
90 }
91
92 pub fn as_str(&self) -> &str
93 where
94 T: AsRef<str>,
95 T::Invalid: AsRef<str>,
96 {
97 match self {
98 Self::Valid(t) => t.as_ref(),
99 Self::Invalid(s) => s.as_ref(),
100 }
101 }
102
103 pub fn map(self, f: impl FnOnce(T) -> T) -> JsonLdLenient<T> {
104 match self {
105 Self::Valid(id) => JsonLdLenient::Valid(f(id)),
106 Self::Invalid(id) => JsonLdLenient::Invalid(id),
107 }
108 }
109}
110
111impl<'a, T, U> JsonLdLenient<&'a T>
112where
113 &'a T: JsonLdValidate<Invalid = &'a U>,
114 T: ?Sized + ToOwned,
115 U: 'a + ?Sized + ToOwned,
116 T::Owned: JsonLdValidate<Invalid = U::Owned>,
117{
118 pub fn into_owned(self) -> JsonLdLenient<T::Owned> {
119 match self {
120 Self::Valid(t) => JsonLdLenient::Valid(t.to_owned()),
121 Self::Invalid(i) => JsonLdLenient::Invalid(i.to_owned()),
122 }
123 }
124}
125
126impl<T> AsRef<str> for JsonLdLenient<T>
127where
128 T: JsonLdValidate + AsRef<str>,
129 T::Invalid: AsRef<str>,
130{
131 fn as_ref(&self) -> &str {
132 self.as_str()
133 }
134}
135
136impl<T> fmt::Display for JsonLdLenient<T>
137where
138 T: JsonLdValidate + fmt::Display,
139 T::Invalid: fmt::Display,
140{
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 match self {
143 Self::Valid(t) => t.fmt(f),
144 Self::Invalid(s) => s.fmt(f),
145 }
146 }
147}
148
149impl<T> FromStr for JsonLdLenient<T>
150where
151 T: JsonLdValidate + FromStr,
152 T::Invalid: From<String>,
153{
154 type Err = Infallible;
155
156 fn from_str(s: &str) -> Result<Self, Self::Err> {
157 Ok(match T::from_str(s) {
158 Ok(t) => Self::Valid(t),
159 Err(_) => Self::Invalid(s.to_owned().into()),
160 })
161 }
162}
163
164impl<T: JsonLdValidate> From<T> for JsonLdLenient<T> {
165 fn from(value: T) -> Self {
166 Self::Valid(value)
167 }
168}
169
170impl<T: JsonLdValidate + FromStr> From<&str> for JsonLdLenient<T>
171where
172 T::Invalid: From<String>,
173{
174 fn from(value: &str) -> Self {
175 let (this, _) = Self::new(value);
176 this
177 }
178}