Skip to main content

json_ld/core/
lenient.rs

1use std::{convert::Infallible, fmt, ops::Deref, str::FromStr};
2
3pub trait JsonLdValidate {
4	type Invalid;
5}
6
7/// String-like value that can be valid or invalid.
8#[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	/// Checks if this is a valid reference.
40	///
41	/// Returns `true` is this reference is a node identifier or a blank node identifier,
42	/// `false` otherwise.
43	#[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}