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