1use std::{
2 borrow::{Borrow, Cow},
3 fmt::Display,
4 ops::Deref,
5};
6
7pub use self::error::InvalidRaw;
8
9mod error {
10 use std::error::Error;
11 use std::fmt::Display;
12
13 #[derive(Debug)]
15 pub struct InvalidRaw;
16
17 impl Display for InvalidRaw {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 write!(f, "raw section must not be empty once end-trimmed")
20 }
21 }
22
23 impl Error for InvalidRaw {}
24}
25
26#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
28#[must_use]
29pub struct Raw<'a>(Cow<'a, str>);
30
31impl<'a> Raw<'a> {
32 pub fn from_cow(src: Cow<'a, str>) -> Result<Self, InvalidRaw> {
37 let trimmed = match src {
38 Cow::Borrowed(string) => Cow::Borrowed(string.trim_end()),
39 Cow::Owned(mut string) => {
40 string.truncate(string.trim_end().len());
41
42 Cow::Owned(string)
43 }
44 };
45
46 if trimmed.is_empty() {
47 return Err(InvalidRaw);
48 }
49
50 Ok(Self(trimmed))
51 }
52
53 pub unsafe fn from_cow_unchecked(src: Cow<'a, str>) -> Self {
62 if cfg!(debug_assertions) {
63 match Self::from_cow(src) {
64 Ok(val) => val,
65 Err(err) => {
66 panic!("Raw::from_cow_unchecked(): {err}")
67 }
68 }
69 } else {
70 Self(src)
71 }
72 }
73
74 #[must_use]
75 pub fn as_str(&self) -> &str {
76 &self.0
77 }
78}
79
80impl Display for Raw<'_> {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 self.as_str().fmt(f)
83 }
84}
85
86impl Deref for Raw<'_> {
87 type Target = str;
88
89 fn deref(&self) -> &Self::Target {
90 self.as_str()
91 }
92}
93
94impl Borrow<str> for Raw<'_> {
95 fn borrow(&self) -> &str {
96 self.as_str()
97 }
98}
99
100impl<'a> TryFrom<&'a str> for Raw<'a> {
101 type Error = InvalidRaw;
102 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
103 Self::from_cow(Cow::Borrowed(value))
104 }
105}
106
107impl<'a> TryFrom<String> for Raw<'a> {
108 type Error = InvalidRaw;
109 fn try_from(value: String) -> Result<Self, Self::Error> {
110 Self::from_cow(Cow::Owned(value))
111 }
112}
113
114impl<'a> TryFrom<Cow<'a, str>> for Raw<'a> {
115 type Error = InvalidRaw;
116 fn try_from(value: Cow<'a, str>) -> Result<Self, Self::Error> {
117 Self::from_cow(value)
118 }
119}