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 {
with_span(span: std::ops::Range<usize>) -> Self15     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
as_str(&self) -> Option<&str>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 
to_str<'s>(&'s self, input: &'s str) -> &'s str32     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 
to_str_with_default<'s>( &'s self, input: Option<&'s str>, default: &'s str, ) -> &'s str42     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
span(&self) -> Option<std::ops::Range<usize>>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 
despan(&mut self, input: &str)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")]
encode(&self, buf: &mut dyn std::fmt::Write, input: &str) -> std::fmt::Result84     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")]
encode_with_default( &self, buf: &mut dyn std::fmt::Write, input: Option<&str>, default: &str, ) -> std::fmt::Result93     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 {
default() -> Self108     fn default() -> Self {
109         Self(RawStringInner::Empty)
110     }
111 }
112 
113 impl std::fmt::Debug for RawString {
114     #[inline]
fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error>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) => write!(formatter, "{:?}", s),
119             RawStringInner::Spanned(s) => write!(formatter, "{:?}", s),
120         }
121     }
122 }
123 
124 impl From<&str> for RawString {
125     #[inline]
from(s: &str) -> Self126     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]
from(s: String) -> Self137     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]
from(s: &String) -> Self148     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]
from(inner: InternalString) -> Self159     fn from(inner: InternalString) -> Self {
160         Self(RawStringInner::Explicit(inner))
161     }
162 }
163 
164 impl From<&InternalString> for RawString {
165     #[inline]
from(s: &InternalString) -> Self166     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]
from(s: Box<str>) -> Self177     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