1use alloc::borrow::ToOwned;
16use alloc::string::String;
17use alloc::sync::Arc;
18use core::borrow::Borrow;
19use core::cmp::Ordering;
20use core::fmt;
21use core::hash::{Hash, Hasher};
22use core::ops::Deref;
23
24pub use rxml_validation::{CompactString, Error, Name, NameStr, NcName, NcNameStr};
25
26use crate::error::{Error as XmlError, ErrorContext};
27
28enum Shared {
29 Static(&'static str),
30 Ptr(Arc<String>),
31}
32
33enum Inner {
34 Owned(String),
35 Shared(Shared),
36}
37
38pub struct Namespace(Inner);
71
72const fn xml() -> Namespace {
73 Namespace(Inner::Shared(Shared::Static(crate::XMLNS_XML)))
74}
75
76const fn xmlns() -> Namespace {
77 Namespace(Inner::Shared(Shared::Static(crate::XMLNS_XMLNS)))
78}
79
80const fn none() -> Namespace {
81 Namespace(Inner::Shared(Shared::Static(
82 crate::parser::XMLNS_UNNAMESPACED,
83 )))
84}
85
86impl Namespace {
87 pub const XML: Namespace = xml();
91
92 pub const XMLNS: Namespace = xmlns();
96
97 pub const NONE: Namespace = none();
99
100 #[inline(always)]
112 pub fn xml() -> &'static Self {
113 static RESULT: Namespace = Namespace::XML;
114 &RESULT
115 }
116
117 #[inline(always)]
129 pub fn xmlns() -> &'static Self {
130 static RESULT: Namespace = Namespace::XMLNS;
131 &RESULT
132 }
133
134 #[inline(always)]
144 pub fn none() -> &'static Self {
145 static RESULT: Namespace = Namespace::NONE;
146 &RESULT
147 }
148
149 pub fn try_share_static(s: &str) -> Option<Self> {
158 if s.is_empty() {
159 return Some(Self::NONE);
160 }
161 if s == crate::XMLNS_XML {
162 return Some(Self::XML);
163 }
164 if s == crate::XMLNS_XMLNS {
165 return Some(Self::XMLNS);
166 }
167 None
168 }
169
170 pub const fn from_str(s: &'static str) -> Self {
183 Self(Inner::Shared(Shared::Static(s)))
184 }
185
186 pub fn make_mut(&mut self) -> &mut String {
192 match self.0 {
193 Inner::Shared(Shared::Static(v)) => {
194 let mut tmp = Inner::Owned(v.to_owned());
195 core::mem::swap(&mut self.0, &mut tmp);
196 let Inner::Owned(ref mut v) = self.0 else {
197 unreachable!()
198 };
199 v
200 }
201 Inner::Shared(Shared::Ptr(ref mut v)) => Arc::make_mut(v),
202 Inner::Owned(ref mut v) => v,
203 }
204 }
205
206 pub fn make_shared(&mut self) {
213 if let Inner::Owned(ref mut v) = self.0 {
214 if let Some(result) = Self::try_share_static(v) {
215 *self = result;
216 return;
217 }
218 let mut tmp = String::new();
219 core::mem::swap(&mut tmp, v);
220 self.0 = Inner::Shared(Shared::Ptr(Arc::new(tmp)));
221 }
222 }
223
224 pub fn share(&mut self) -> Self {
229 self.make_shared();
230 self.clone()
231 }
232
233 pub fn shared(mut self) -> Self {
236 self.make_shared();
237 self.clone()
238 }
239
240 pub fn clone_shared(&self) -> Self {
243 self.clone().shared()
244 }
245
246 pub fn as_namespace_name(&self) -> Option<&str> {
249 let s = self.deref();
250 if s.is_empty() {
251 None
252 } else {
253 Some(s)
254 }
255 }
256
257 pub fn is_none(&self) -> bool {
262 self.deref().is_empty()
263 }
264
265 pub fn is_some(&self) -> bool {
267 !self.deref().is_empty()
268 }
269
270 pub fn as_str(&self) -> &str {
272 self.deref()
273 }
274}
275
276impl Deref for Namespace {
277 type Target = str;
278
279 fn deref(&self) -> &Self::Target {
280 match self.0 {
281 Inner::Shared(Shared::Static(v)) => v,
282 Inner::Shared(Shared::Ptr(ref v)) => v.deref().deref(),
283 Inner::Owned(ref v) => v.deref(),
284 }
285 }
286}
287
288impl AsRef<str> for Namespace {
289 fn as_ref(&self) -> &str {
290 self.deref()
291 }
292}
293
294impl Borrow<str> for Namespace {
295 fn borrow(&self) -> &str {
296 self.deref()
297 }
298}
299
300impl Clone for Namespace {
301 fn clone(&self) -> Self {
302 Self(match self.0 {
303 Inner::Shared(Shared::Static(v)) => Inner::Shared(Shared::Static(v)),
304 Inner::Shared(Shared::Ptr(ref v)) => Inner::Shared(Shared::Ptr(Arc::clone(v))),
305 Inner::Owned(ref v) => Inner::Owned(v.clone()),
306 })
307 }
308}
309
310impl fmt::Debug for Namespace {
311 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
312 let mut wrapper = match self.0 {
313 Inner::Shared(Shared::Static(_)) => f.debug_tuple("Namespace<{Static}>"),
314 Inner::Shared(Shared::Ptr(_)) => f.debug_tuple("Namespace<{Ptr}>"),
315 Inner::Owned(_) => f.debug_tuple("Namespace<{Owned}>"),
316 };
317 wrapper.field(&self.deref()).finish()
318 }
319}
320
321impl fmt::Display for Namespace {
322 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
323 <str as fmt::Display>::fmt(self.deref(), f)
324 }
325}
326
327impl Eq for Namespace {}
328
329impl From<Namespace> for String {
330 fn from(other: Namespace) -> Self {
331 match other.0 {
332 Inner::Owned(v) => v,
333 Inner::Shared(Shared::Static(v)) => v.to_owned(),
334 Inner::Shared(Shared::Ptr(v)) => Arc::unwrap_or_clone(v),
335 }
336 }
337}
338
339impl From<Namespace> for Arc<String> {
340 fn from(other: Namespace) -> Self {
341 match other.0 {
342 Inner::Owned(v) => Arc::new(v),
343 Inner::Shared(Shared::Static(v)) => Arc::new(v.to_owned()),
344 Inner::Shared(Shared::Ptr(v)) => v,
345 }
346 }
347}
348
349impl From<Name> for Namespace {
350 fn from(other: Name) -> Self {
351 let v: String = other.into();
352 debug_assert!(!v.is_empty()); Self(Inner::Owned(v))
354 }
355}
356
357impl From<NcName> for Namespace {
358 fn from(other: NcName) -> Self {
359 let v: String = other.into();
360 debug_assert!(!v.is_empty()); Self(Inner::Owned(v))
362 }
363}
364
365impl From<&'static Name> for Namespace {
366 fn from(other: &'static Name) -> Self {
367 let v: &'static str = other.as_ref();
368 debug_assert!(!v.is_empty()); Self(Inner::Shared(Shared::Static(v)))
370 }
371}
372
373impl From<&'static NcName> for Namespace {
374 fn from(other: &'static NcName) -> Self {
375 let v: &'static str = other.as_ref();
376 debug_assert!(!v.is_empty()); Self(Inner::Shared(Shared::Static(v)))
378 }
379}
380
381impl From<&'static str> for Namespace {
382 fn from(other: &'static str) -> Self {
383 Self(Inner::Shared(Shared::Static(other)))
384 }
385}
386
387impl From<String> for Namespace {
388 fn from(other: String) -> Self {
389 if let Some(result) = Self::try_share_static(&other) {
390 return result;
391 }
392 Self(Inner::Owned(other))
393 }
394}
395
396impl From<Arc<String>> for Namespace {
397 fn from(other: Arc<String>) -> Self {
398 if let Some(result) = Self::try_share_static(&other) {
399 return result;
400 }
401 Self(Inner::Shared(Shared::Ptr(other)))
402 }
403}
404
405impl Hash for Namespace {
406 fn hash<H: Hasher>(&self, h: &mut H) {
407 self.deref().hash(h)
408 }
409}
410
411impl Ord for Namespace {
412 fn cmp(&self, other: &Namespace) -> Ordering {
413 self.deref().cmp(other.deref())
414 }
415}
416
417impl PartialEq for Namespace {
418 fn eq(&self, other: &Namespace) -> bool {
419 self.deref() == other.deref()
420 }
421}
422
423impl PartialEq<&str> for Namespace {
424 fn eq(&self, other: &&str) -> bool {
425 self.deref() == *other
426 }
427}
428
429impl PartialEq<Namespace> for &str {
430 fn eq(&self, other: &Namespace) -> bool {
431 *self == other.deref()
432 }
433}
434
435impl PartialEq<str> for Namespace {
436 fn eq(&self, other: &str) -> bool {
437 self.deref() == other
438 }
439}
440
441impl PartialEq<Namespace> for str {
442 fn eq(&self, other: &Namespace) -> bool {
443 self == other.deref()
444 }
445}
446
447impl PartialOrd for Namespace {
448 fn partial_cmp(&self, other: &Namespace) -> Option<Ordering> {
449 Some(self.cmp(other))
450 }
451}
452
453pub fn validate_cdata(s: &str) -> Result<(), XmlError> {
466 rxml_validation::validate_cdata(s).map_err(|e| XmlError::from_validation(e, None))
467}
468
469pub fn validate_name(s: &str) -> Result<(), XmlError> {
486 rxml_validation::validate_name(s)
487 .map_err(|e| XmlError::from_validation(e, Some(ErrorContext::Name)))
488}
489
490pub fn validate_ncname(s: &str) -> Result<(), XmlError> {
504 match rxml_validation::validate_ncname(s)
505 .map_err(|e| XmlError::from_validation(e, Some(ErrorContext::Name)))
506 {
507 Err(XmlError::UnexpectedChar(ctx, ':', _)) => Err(XmlError::MultiColonName(ctx)),
508 Err(XmlError::InvalidSyntax(_)) => Err(XmlError::EmptyNamePart(None)),
509 other => other,
510 }
511}
512
513#[cfg(test)]
514mod tests {
515 use super::*;
516
517 #[test]
518 fn can_slice_namespace_name() {
519 let nsn = Namespace::xml();
520 assert_eq!(&nsn[..4], "http");
521 }
522}