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 | pub(crate) fn encode(&self, buf: &mut dyn std::fmt::Write, input: &str) -> std::fmt::Result { |
84 | let raw = self.to_str(input); |
85 | for part in raw.split(' \r' ) { |
86 | write!(buf, " {}" , part)?; |
87 | } |
88 | Ok(()) |
89 | } |
90 | |
91 | pub(crate) fn encode_with_default( |
92 | &self, |
93 | buf: &mut dyn std::fmt::Write, |
94 | input: Option<&str>, |
95 | default: &str, |
96 | ) -> std::fmt::Result { |
97 | let raw = self.to_str_with_default(input, default); |
98 | for part in raw.split(' \r' ) { |
99 | write!(buf, " {}" , part)?; |
100 | } |
101 | Ok(()) |
102 | } |
103 | } |
104 | |
105 | impl Default for RawString { |
106 | fn default() -> Self { |
107 | Self(RawStringInner::Empty) |
108 | } |
109 | } |
110 | |
111 | impl std::fmt::Debug for RawString { |
112 | #[inline ] |
113 | fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { |
114 | match &self.0 { |
115 | RawStringInner::Empty => write!(formatter, "empty" ), |
116 | RawStringInner::Explicit(s: &InternalString) => write!(formatter, " {:?}" , s), |
117 | RawStringInner::Spanned(s: &Range) => write!(formatter, " {:?}" , s), |
118 | } |
119 | } |
120 | } |
121 | |
122 | impl From<&str> for RawString { |
123 | #[inline ] |
124 | fn from(s: &str) -> Self { |
125 | if s.is_empty() { |
126 | Self(RawStringInner::Empty) |
127 | } else { |
128 | InternalString::from(s).into() |
129 | } |
130 | } |
131 | } |
132 | |
133 | impl From<String> for RawString { |
134 | #[inline ] |
135 | fn from(s: String) -> Self { |
136 | if s.is_empty() { |
137 | Self(RawStringInner::Empty) |
138 | } else { |
139 | InternalString::from(s).into() |
140 | } |
141 | } |
142 | } |
143 | |
144 | impl From<&String> for RawString { |
145 | #[inline ] |
146 | fn from(s: &String) -> Self { |
147 | if s.is_empty() { |
148 | Self(RawStringInner::Empty) |
149 | } else { |
150 | InternalString::from(s).into() |
151 | } |
152 | } |
153 | } |
154 | |
155 | impl From<InternalString> for RawString { |
156 | #[inline ] |
157 | fn from(inner: InternalString) -> Self { |
158 | Self(RawStringInner::Explicit(inner)) |
159 | } |
160 | } |
161 | |
162 | impl From<&InternalString> for RawString { |
163 | #[inline ] |
164 | fn from(s: &InternalString) -> Self { |
165 | if s.is_empty() { |
166 | Self(RawStringInner::Empty) |
167 | } else { |
168 | InternalString::from(s).into() |
169 | } |
170 | } |
171 | } |
172 | |
173 | impl From<Box<str>> for RawString { |
174 | #[inline ] |
175 | fn from(s: Box<str>) -> Self { |
176 | if s.is_empty() { |
177 | Self(RawStringInner::Empty) |
178 | } else { |
179 | InternalString::from(s).into() |
180 | } |
181 | } |
182 | } |
183 | |