use crate::InternalString; /// Opaque string storage for raw TOML; internal to `toml_edit` #[derive(PartialEq, Eq, Clone, Hash)] pub struct RawString(RawStringInner); #[derive(PartialEq, Eq, Clone, Hash)] enum RawStringInner { Empty, Explicit(InternalString), Spanned(std::ops::Range), } impl RawString { pub(crate) fn with_span(span: std::ops::Range) -> Self { if span.start == span.end { RawString(RawStringInner::Empty) } else { RawString(RawStringInner::Spanned(span)) } } /// Access the underlying string pub fn as_str(&self) -> Option<&str> { match &self.0 { RawStringInner::Empty => Some(""), RawStringInner::Explicit(s) => Some(s.as_str()), RawStringInner::Spanned(_) => None, } } pub(crate) fn to_str<'s>(&'s self, input: &'s str) -> &'s str { match &self.0 { RawStringInner::Empty => "", RawStringInner::Explicit(s) => s.as_str(), RawStringInner::Spanned(span) => input.get(span.clone()).unwrap_or_else(|| { panic!("span {:?} should be in input:\n```\n{}\n```", span, input) }), } } pub(crate) fn to_str_with_default<'s>( &'s self, input: Option<&'s str>, default: &'s str, ) -> &'s str { match &self.0 { RawStringInner::Empty => "", RawStringInner::Explicit(s) => s.as_str(), RawStringInner::Spanned(span) => { if let Some(input) = input { input.get(span.clone()).unwrap_or_else(|| { panic!("span {:?} should be in input:\n```\n{}\n```", span, input) }) } else { default } } } } /// Access the underlying span pub(crate) fn span(&self) -> Option> { match &self.0 { RawStringInner::Empty => None, RawStringInner::Explicit(_) => None, RawStringInner::Spanned(span) => Some(span.clone()), } } pub(crate) fn despan(&mut self, input: &str) { match &self.0 { RawStringInner::Empty => {} RawStringInner::Explicit(_) => {} RawStringInner::Spanned(span) => { *self = Self::from(input.get(span.clone()).unwrap_or_else(|| { panic!("span {:?} should be in input:\n```\n{}\n```", span, input) })) } } } pub(crate) fn encode(&self, buf: &mut dyn std::fmt::Write, input: &str) -> std::fmt::Result { let raw = self.to_str(input); for part in raw.split('\r') { write!(buf, "{}", part)?; } Ok(()) } pub(crate) fn encode_with_default( &self, buf: &mut dyn std::fmt::Write, input: Option<&str>, default: &str, ) -> std::fmt::Result { let raw = self.to_str_with_default(input, default); for part in raw.split('\r') { write!(buf, "{}", part)?; } Ok(()) } } impl Default for RawString { fn default() -> Self { Self(RawStringInner::Empty) } } impl std::fmt::Debug for RawString { #[inline] fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match &self.0 { RawStringInner::Empty => write!(formatter, "empty"), RawStringInner::Explicit(s) => write!(formatter, "{:?}", s), RawStringInner::Spanned(s) => write!(formatter, "{:?}", s), } } } impl From<&str> for RawString { #[inline] fn from(s: &str) -> Self { if s.is_empty() { Self(RawStringInner::Empty) } else { InternalString::from(s).into() } } } impl From for RawString { #[inline] fn from(s: String) -> Self { if s.is_empty() { Self(RawStringInner::Empty) } else { InternalString::from(s).into() } } } impl From<&String> for RawString { #[inline] fn from(s: &String) -> Self { if s.is_empty() { Self(RawStringInner::Empty) } else { InternalString::from(s).into() } } } impl From for RawString { #[inline] fn from(inner: InternalString) -> Self { Self(RawStringInner::Explicit(inner)) } } impl From<&InternalString> for RawString { #[inline] fn from(s: &InternalString) -> Self { if s.is_empty() { Self(RawStringInner::Empty) } else { InternalString::from(s).into() } } } impl From> for RawString { #[inline] fn from(s: Box) -> Self { if s.is_empty() { Self(RawStringInner::Empty) } else { InternalString::from(s).into() } } }