use std::fmt::Display;
use bstr::{BStr, BString};
use crate::parse::{Event, EventRef};
impl Event {
pub(crate) fn rebase(&mut self, offset: usize) -> Result<(), crate::parse::span::Error> {
match self {
Event::Comment(comment) => comment.text.rebase(offset),
Event::SectionHeader(header) => header.rebase(offset),
Event::SectionValueName(name) => name.rebase(offset),
Event::Value(bytes)
| Event::Newline(bytes)
| Event::ValueNotDone(bytes)
| Event::ValueDone(bytes)
| Event::Whitespace(bytes) => bytes.rebase(offset),
Event::KeyValueSeparator => Ok(()),
}
}
pub(crate) fn copy_to_backing_in(
&self,
source: &[u8],
target: &mut Vec<u8>,
) -> Result<Event, crate::parse::span::Error> {
Ok(match self {
Event::Comment(comment) => Event::Comment(comment.copy_to_backing_in(source, target)?),
Event::SectionHeader(header) => Event::SectionHeader(header.copy_to_backing_in(source, target)?),
Event::SectionValueName(name) => Event::SectionValueName(name.copy_to_backing_in(source, target)?),
Event::Value(bytes) => Event::Value(bytes.copy_to_backing_in(source, target)?),
Event::Newline(bytes) => Event::Newline(bytes.copy_to_backing_in(source, target)?),
Event::ValueNotDone(bytes) => Event::ValueNotDone(bytes.copy_to_backing_in(source, target)?),
Event::ValueDone(bytes) => Event::ValueDone(bytes.copy_to_backing_in(source, target)?),
Event::Whitespace(bytes) => Event::Whitespace(bytes.copy_to_backing_in(source, target)?),
Event::KeyValueSeparator => Event::KeyValueSeparator,
})
}
pub(crate) fn as_ref_in<'a>(&'a self, backing: &'a [u8]) -> EventRef<'a> {
match self {
Event::Comment(comment) => EventRef::Comment {
tag: comment.tag,
text: comment.text.as_bstr_in(backing),
},
Event::SectionHeader(header) => EventRef::SectionHeader {
name: header.name.as_bstr_in(backing),
separator: header.separator.as_ref().map(|separator| separator.as_bstr_in(backing)),
subsection_name: header
.subsection_name
.as_ref()
.map(|subsection_name| subsection_name.value_in(backing)),
},
Event::SectionValueName(name) => EventRef::SectionValueName(name.as_bstr_in(backing)),
Event::Value(bytes) => EventRef::Value(bytes.as_bstr_in(backing)),
Event::Newline(bytes) => EventRef::Newline(bytes.as_bstr_in(backing)),
Event::ValueNotDone(bytes) => EventRef::ValueNotDone(bytes.as_bstr_in(backing)),
Event::ValueDone(bytes) => EventRef::ValueDone(bytes.as_bstr_in(backing)),
Event::Whitespace(bytes) => EventRef::Whitespace(bytes.as_bstr_in(backing)),
Event::KeyValueSeparator => EventRef::KeyValueSeparator,
}
}
pub(crate) fn to_bstr_lossy_in<'a>(&'a self, backing: &'a [u8]) -> &'a BStr {
match self {
Self::ValueNotDone(e) | Self::Whitespace(e) | Self::Newline(e) | Self::Value(e) | Self::ValueDone(e) => {
e.as_bstr_in(backing)
}
Self::KeyValueSeparator => "=".into(),
Self::SectionValueName(k) => k.as_bstr_in(backing),
Self::SectionHeader(h) => h.name.as_bstr_in(backing),
Self::Comment(c) => c.text.as_bstr_in(backing),
}
}
pub(crate) fn write_to_in(&self, backing: &[u8], out: &mut dyn std::io::Write) -> std::io::Result<()> {
match self {
Self::ValueNotDone(e) => {
out.write_all(e.as_slice_in(backing))?;
out.write_all(br"\")
}
Self::Whitespace(e) | Self::Newline(e) | Self::Value(e) | Self::ValueDone(e) => {
out.write_all(e.as_slice_in(backing))
}
Self::KeyValueSeparator => out.write_all(b"="),
Self::SectionValueName(k) => out.write_all(k.as_slice_in(backing)),
Self::SectionHeader(h) => h.write_to_in(backing, out),
Self::Comment(c) => c.write_to_in(backing, out),
}
}
}
impl EventRef<'_> {
pub fn to_bstr_lossy(&self) -> &BStr {
match self {
EventRef::ValueNotDone(bytes)
| EventRef::Whitespace(bytes)
| EventRef::Newline(bytes)
| EventRef::Value(bytes)
| EventRef::ValueDone(bytes) => bytes,
EventRef::KeyValueSeparator => "=".into(),
EventRef::SectionValueName(name) => name,
EventRef::SectionHeader { name, .. } => name,
EventRef::Comment { text, .. } => text,
}
}
pub fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> {
match self {
EventRef::ValueNotDone(bytes) => {
out.write_all(bytes)?;
out.write_all(br"\")
}
EventRef::Whitespace(bytes)
| EventRef::Newline(bytes)
| EventRef::Value(bytes)
| EventRef::ValueDone(bytes) => out.write_all(bytes),
EventRef::KeyValueSeparator => out.write_all(b"="),
EventRef::SectionValueName(name) => out.write_all(name),
EventRef::SectionHeader {
name,
separator,
subsection_name,
} => {
out.write_all(b"[")?;
out.write_all(name)?;
if let (Some(separator), Some(subsection_name)) = (separator, subsection_name) {
out.write_all(separator)?;
if *separator == b"." {
out.write_all(subsection_name)?;
} else {
out.write_all(b"\"")?;
crate::parse::section::header::write_escaped_subsection(subsection_name, &mut *out)?;
out.write_all(b"\"")?;
}
}
out.write_all(b"]")
}
EventRef::Comment { tag, text } => {
out.write_all(&[*tag])?;
out.write_all(text)
}
}
}
}
impl Display for EventRef<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&BString::from(self), f)
}
}
impl From<&EventRef<'_>> for BString {
fn from(event: &EventRef<'_>) -> Self {
let mut buf = Vec::new();
event.write_to(&mut buf).expect("io error impossible");
buf.into()
}
}