1#[derive(PartialEq, Eq, Clone, Hash)]
3pub struct RawString(RawStringInner);
4
5#[derive(PartialEq, Eq, Clone, Hash)]
6enum RawStringInner {
7 Empty,
8 Explicit(String),
9 Spanned(std::ops::Range<usize>),
10}
11
12impl RawString {
13 pub(crate) fn with_span(span: std::ops::Range<usize>) -> Self {
14 Self(RawStringInner::Spanned(span))
15 }
16
17 pub fn as_str(&self) -> Option<&str> {
21 match &self.0 {
22 RawStringInner::Empty => Some(""),
23 RawStringInner::Explicit(s) => Some(s.as_str()),
24 RawStringInner::Spanned(_) => None,
25 }
26 }
27
28 pub fn span(&self) -> Option<std::ops::Range<usize>> {
32 match &self.0 {
33 RawStringInner::Empty => None,
34 RawStringInner::Explicit(_) => None,
35 RawStringInner::Spanned(span) => Some(span.clone()),
36 }
37 }
38
39 pub(crate) fn to_str<'s>(&'s self, input: &'s str) -> &'s str {
40 match &self.0 {
41 RawStringInner::Empty => "",
42 RawStringInner::Explicit(s) => s.as_str(),
43 RawStringInner::Spanned(span) => input
44 .get(span.clone())
45 .unwrap_or_else(|| panic!("span {span:?} should be in input:\n```\n{input}\n```")),
46 }
47 }
48
49 pub(crate) fn to_str_with_default<'s>(
50 &'s self,
51 input: Option<&'s str>,
52 default: &'s str,
53 ) -> &'s str {
54 match &self.0 {
55 RawStringInner::Empty => "",
56 RawStringInner::Explicit(s) => s.as_str(),
57 RawStringInner::Spanned(span) => {
58 if let Some(input) = input {
59 input.get(span.clone()).unwrap_or_else(|| {
60 panic!("span {span:?} should be in input:\n```\n{input}\n```")
61 })
62 } else {
63 default
64 }
65 }
66 }
67 }
68
69 pub(crate) fn despan(&mut self, input: &str) {
70 match &self.0 {
71 RawStringInner::Empty => {}
72 RawStringInner::Explicit(_) => {}
73 RawStringInner::Spanned(span) => {
74 if span.start == span.end {
75 *self = Self(RawStringInner::Empty);
76 } else {
77 *self = Self::from(input.get(span.clone()).unwrap_or_else(|| {
78 panic!("span {span:?} should be in input:\n```\n{input}\n```")
79 }));
80 }
81 }
82 }
83 }
84
85 #[cfg(feature = "display")]
86 pub(crate) fn encode(&self, buf: &mut dyn std::fmt::Write, input: &str) -> std::fmt::Result {
87 let raw = self.to_str(input);
88 for part in raw.split('\r') {
89 write!(buf, "{part}")?;
90 }
91 Ok(())
92 }
93
94 #[cfg(feature = "display")]
95 pub(crate) fn encode_with_default(
96 &self,
97 buf: &mut dyn std::fmt::Write,
98 input: Option<&str>,
99 default: &str,
100 ) -> std::fmt::Result {
101 let raw = self.to_str_with_default(input, default);
102 for part in raw.split('\r') {
103 write!(buf, "{part}")?;
104 }
105 Ok(())
106 }
107}
108
109impl Default for RawString {
110 fn default() -> Self {
111 Self(RawStringInner::Empty)
112 }
113}
114
115impl std::fmt::Debug for RawString {
116 #[inline]
117 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
118 match &self.0 {
119 RawStringInner::Empty => write!(formatter, "empty"),
120 RawStringInner::Explicit(s) => write!(formatter, "{s:?}"),
121 RawStringInner::Spanned(s) => write!(formatter, "{s:?}"),
122 }
123 }
124}
125
126impl From<&str> for RawString {
127 #[inline]
128 fn from(s: &str) -> Self {
129 if s.is_empty() {
130 Self(RawStringInner::Empty)
131 } else {
132 String::from(s).into()
133 }
134 }
135}
136
137impl From<String> for RawString {
138 #[inline]
139 fn from(s: String) -> Self {
140 if s.is_empty() {
141 Self(RawStringInner::Empty)
142 } else {
143 Self(RawStringInner::Explicit(s))
144 }
145 }
146}
147
148impl From<&String> for RawString {
149 #[inline]
150 fn from(s: &String) -> Self {
151 if s.is_empty() {
152 Self(RawStringInner::Empty)
153 } else {
154 String::from(s).into()
155 }
156 }
157}
158
159impl From<Box<str>> for RawString {
160 #[inline]
161 fn from(s: Box<str>) -> Self {
162 if s.is_empty() {
163 Self(RawStringInner::Empty)
164 } else {
165 String::from(s).into()
166 }
167 }
168}