Skip to main content

toml_edit/
raw_string.rs

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