json_ld_syntax/
lang.rs

1pub use langtag::{InvalidLangTag, LangTag, LangTagBuf};
2use std::{borrow::Borrow, fmt, hash::Hash, ops::Deref};
3
4use crate::utils::{case_insensitive_cmp, case_insensitive_eq, case_insensitive_hash};
5
6/// Language tag that may not be well-formed.
7#[derive(Debug)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize))]
9#[cfg_attr(feature = "serde", serde(transparent))]
10pub struct LenientLangTag(str);
11
12impl LenientLangTag {
13	pub fn new(s: &str) -> (&Self, Option<InvalidLangTag<&str>>) {
14		let err = LangTag::new(s).err();
15		(unsafe { std::mem::transmute::<&str, &Self>(s) }, err)
16	}
17
18	pub fn as_bytes(&self) -> &[u8] {
19		self.0.as_bytes()
20	}
21
22	pub fn as_str(&self) -> &str {
23		&self.0
24	}
25
26	pub fn is_well_formed(&self) -> bool {
27		LangTag::new(self.as_str()).is_ok()
28	}
29
30	pub fn as_well_formed(&self) -> Option<&LangTag> {
31		LangTag::new(self.as_str()).ok()
32	}
33}
34
35impl PartialEq for LenientLangTag {
36	fn eq(&self, other: &Self) -> bool {
37		case_insensitive_eq(self.as_bytes(), other.as_bytes())
38	}
39}
40
41impl Eq for LenientLangTag {}
42
43impl PartialOrd for LenientLangTag {
44	fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
45		Some(self.cmp(other))
46	}
47}
48
49impl Ord for LenientLangTag {
50	fn cmp(&self, other: &Self) -> std::cmp::Ordering {
51		case_insensitive_cmp(self.as_bytes(), other.as_bytes())
52	}
53}
54
55impl Hash for LenientLangTag {
56	fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
57		case_insensitive_hash(self.as_bytes(), state)
58	}
59}
60
61impl ToOwned for LenientLangTag {
62	type Owned = LenientLangTagBuf;
63
64	fn to_owned(&self) -> Self::Owned {
65		LenientLangTagBuf(self.0.to_owned())
66	}
67}
68
69impl Borrow<str> for LenientLangTag {
70	fn borrow(&self) -> &str {
71		self.as_str()
72	}
73}
74
75impl AsRef<str> for LenientLangTag {
76	fn as_ref(&self) -> &str {
77		self.as_str()
78	}
79}
80
81impl fmt::Display for LenientLangTag {
82	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83		self.0.fmt(f)
84	}
85}
86
87/// Owned language tag that may not be well-formed.
88#[derive(Debug, Clone)]
89pub struct LenientLangTagBuf(String);
90
91impl LenientLangTagBuf {
92	pub fn new(s: String) -> (Self, Option<InvalidLangTag<String>>) {
93		let err = LangTag::new(s.as_str())
94			.err()
95			.map(|InvalidLangTag(s)| InvalidLangTag(s.to_owned()));
96		(Self(s), err)
97	}
98
99	pub fn as_lenient_lang_tag_ref(&self) -> &LenientLangTag {
100		unsafe { std::mem::transmute(self.0.as_str()) }
101	}
102
103	pub fn into_string(self) -> String {
104		self.0
105	}
106
107	pub fn into_well_formed(self) -> Result<LangTagBuf, InvalidLangTag<String>> {
108		LangTagBuf::new(self.0)
109	}
110}
111
112impl Deref for LenientLangTagBuf {
113	type Target = LenientLangTag;
114
115	fn deref(&self) -> &Self::Target {
116		self.as_lenient_lang_tag_ref()
117	}
118}
119
120impl PartialEq for LenientLangTagBuf {
121	fn eq(&self, other: &Self) -> bool {
122		self.as_lenient_lang_tag_ref()
123			.eq(other.as_lenient_lang_tag_ref())
124	}
125}
126
127impl Eq for LenientLangTagBuf {}
128
129impl PartialOrd for LenientLangTagBuf {
130	fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
131		Some(self.cmp(other))
132	}
133}
134
135impl Ord for LenientLangTagBuf {
136	fn cmp(&self, other: &Self) -> std::cmp::Ordering {
137		self.as_lenient_lang_tag_ref()
138			.cmp(other.as_lenient_lang_tag_ref())
139	}
140}
141
142impl Hash for LenientLangTagBuf {
143	fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
144		self.as_lenient_lang_tag_ref().hash(state)
145	}
146}
147
148impl Borrow<LenientLangTag> for LenientLangTagBuf {
149	fn borrow(&self) -> &LenientLangTag {
150		self.as_lenient_lang_tag_ref()
151	}
152}
153
154impl AsRef<LenientLangTag> for LenientLangTagBuf {
155	fn as_ref(&self) -> &LenientLangTag {
156		self.as_lenient_lang_tag_ref()
157	}
158}
159
160impl From<LangTagBuf> for LenientLangTagBuf {
161	fn from(tag: LangTagBuf) -> Self {
162		Self(tag.into_string())
163	}
164}
165
166impl From<String> for LenientLangTagBuf {
167	fn from(tag: String) -> Self {
168		Self(tag)
169	}
170}
171
172impl fmt::Display for LenientLangTagBuf {
173	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174		self.0.fmt(f)
175	}
176}
177
178#[cfg(feature = "serde")]
179impl serde::Serialize for LenientLangTagBuf {
180	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
181	where
182		S: serde::Serializer,
183	{
184		self.as_str().serialize(serializer)
185	}
186}
187
188#[cfg(feature = "serde")]
189impl<'de> serde::Deserialize<'de> for LenientLangTagBuf {
190	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
191	where
192		D: serde::Deserializer<'de>,
193	{
194		Ok(Self(String::deserialize(deserializer)?))
195	}
196}