toml_edit/
raw_string.rs

1use crate::InternalString;
2
3/// Opaque string storage for raw TOML; internal to `toml_edit`
4#[derive(PartialEq, Eq, Clone, Hash)]
5pub struct RawString(RawStringInner);
6
7#[derive(PartialEq, Eq, Clone, Hash)]
8enum RawStringInner {
9    Empty,
10    Explicit(InternalString),
11    Spanned(std::ops::Range<usize>),
12}
13
14impl 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
105impl Default for RawString {
106    fn default() -> Self {
107        Self(RawStringInner::Empty)
108    }
109}
110
111impl 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) => write!(formatter, "{:?}", s),
117            RawStringInner::Spanned(s) => write!(formatter, "{:?}", s),
118        }
119    }
120}
121
122impl 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
133impl 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
144impl 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
155impl From<InternalString> for RawString {
156    #[inline]
157    fn from(inner: InternalString) -> Self {
158        Self(RawStringInner::Explicit(inner))
159    }
160}
161
162impl 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
173impl 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}