use super::{write, Arguments, FormatElement};
use crate::format_element::Interned;
use crate::prelude::{LineMode, PrintMode, Tag};
use crate::{Format, FormatResult, FormatState};
use rustc_hash::FxHashMap;
use std::any::{Any, TypeId};
use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
pub trait Buffer {
type Context;
fn write_element(&mut self, element: FormatElement) -> FormatResult<()>;
#[doc(hidden)]
fn elements(&self) -> &[FormatElement];
fn write_fmt(mut self: &mut Self, arguments: Arguments<Self::Context>) -> FormatResult<()> {
write(&mut self, arguments)
}
fn state(&self) -> &FormatState<Self::Context>;
fn state_mut(&mut self) -> &mut FormatState<Self::Context>;
fn snapshot(&self) -> BufferSnapshot;
fn restore_snapshot(&mut self, snapshot: BufferSnapshot);
}
#[derive(Debug)]
pub enum BufferSnapshot {
Position(usize),
Any(Box<dyn Any>),
}
impl BufferSnapshot {
pub const fn position(index: usize) -> Self {
Self::Position(index)
}
pub fn unwrap_position(&self) -> usize {
match self {
BufferSnapshot::Position(index) => *index,
BufferSnapshot::Any(_) => panic!("Tried to unwrap Any snapshot as a position."),
}
}
pub fn unwrap_any<T: 'static>(self) -> T {
match self {
BufferSnapshot::Position(_) => {
panic!("Tried to unwrap Position snapshot as Any snapshot.")
}
BufferSnapshot::Any(value) => match value.downcast::<T>() {
Ok(snapshot) => *snapshot,
Err(err) => {
panic!(
"Tried to unwrap snapshot of type {:?} as {:?}",
(*err).type_id(),
TypeId::of::<T>()
)
}
},
}
}
}
impl<W: Buffer<Context = Context> + ?Sized, Context> Buffer for &mut W {
type Context = Context;
fn write_element(&mut self, element: FormatElement) -> FormatResult<()> {
(**self).write_element(element)
}
fn elements(&self) -> &[FormatElement] {
(**self).elements()
}
fn write_fmt(&mut self, args: Arguments<Context>) -> FormatResult<()> {
(**self).write_fmt(args)
}
fn state(&self) -> &FormatState<Self::Context> {
(**self).state()
}
fn state_mut(&mut self) -> &mut FormatState<Self::Context> {
(**self).state_mut()
}
fn snapshot(&self) -> BufferSnapshot {
(**self).snapshot()
}
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
(**self).restore_snapshot(snapshot)
}
}
#[derive(Debug)]
pub struct VecBuffer<'a, Context> {
state: &'a mut FormatState<Context>,
elements: Vec<FormatElement>,
}
impl<'a, Context> VecBuffer<'a, Context> {
pub fn new(state: &'a mut FormatState<Context>) -> Self {
Self::new_with_vec(state, Vec::new())
}
pub fn new_with_vec(state: &'a mut FormatState<Context>, elements: Vec<FormatElement>) -> Self {
Self { state, elements }
}
pub fn with_capacity(capacity: usize, state: &'a mut FormatState<Context>) -> Self {
Self {
state,
elements: Vec::with_capacity(capacity),
}
}
pub fn into_vec(self) -> Vec<FormatElement> {
self.elements
}
pub fn take_vec(&mut self) -> Vec<FormatElement> {
std::mem::take(&mut self.elements)
}
}
impl<Context> Deref for VecBuffer<'_, Context> {
type Target = [FormatElement];
fn deref(&self) -> &Self::Target {
&self.elements
}
}
impl<Context> DerefMut for VecBuffer<'_, Context> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.elements
}
}
impl<Context> Buffer for VecBuffer<'_, Context> {
type Context = Context;
fn write_element(&mut self, element: FormatElement) -> FormatResult<()> {
self.elements.push(element);
Ok(())
}
fn elements(&self) -> &[FormatElement] {
self
}
fn state(&self) -> &FormatState<Self::Context> {
self.state
}
fn state_mut(&mut self) -> &mut FormatState<Self::Context> {
self.state
}
fn snapshot(&self) -> BufferSnapshot {
BufferSnapshot::position(self.elements.len())
}
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
let position = snapshot.unwrap_position();
assert!(
self.elements.len() >= position,
r#"Outdated snapshot. This buffer contains fewer elements than at the time the snapshot was taken.
Make sure that you take and restore the snapshot in order and that this snapshot belongs to the current buffer."#
);
self.elements.truncate(position);
}
}
pub struct PreambleBuffer<'buf, Preamble, Context> {
inner: &'buf mut dyn Buffer<Context = Context>,
preamble: Preamble,
empty: bool,
}
impl<'buf, Preamble, Context> PreambleBuffer<'buf, Preamble, Context> {
pub fn new(inner: &'buf mut dyn Buffer<Context = Context>, preamble: Preamble) -> Self {
Self {
inner,
preamble,
empty: true,
}
}
pub fn did_write_preamble(&self) -> bool {
!self.empty
}
}
impl<Preamble, Context> Buffer for PreambleBuffer<'_, Preamble, Context>
where
Preamble: Format<Context>,
{
type Context = Context;
fn write_element(&mut self, element: FormatElement) -> FormatResult<()> {
if self.empty {
write!(self.inner, [&self.preamble])?;
self.empty = false;
}
self.inner.write_element(element)
}
fn elements(&self) -> &[FormatElement] {
self.inner.elements()
}
fn state(&self) -> &FormatState<Self::Context> {
self.inner.state()
}
fn state_mut(&mut self) -> &mut FormatState<Self::Context> {
self.inner.state_mut()
}
fn snapshot(&self) -> BufferSnapshot {
BufferSnapshot::Any(Box::new(PreambleBufferSnapshot {
inner: self.inner.snapshot(),
empty: self.empty,
}))
}
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
let snapshot = snapshot.unwrap_any::<PreambleBufferSnapshot>();
self.empty = snapshot.empty;
self.inner.restore_snapshot(snapshot.inner);
}
}
struct PreambleBufferSnapshot {
inner: BufferSnapshot,
empty: bool,
}
pub struct Inspect<'inner, Context, Inspector> {
inner: &'inner mut dyn Buffer<Context = Context>,
inspector: Inspector,
}
impl<'inner, Context, Inspector> Inspect<'inner, Context, Inspector> {
fn new(inner: &'inner mut dyn Buffer<Context = Context>, inspector: Inspector) -> Self {
Self { inner, inspector }
}
}
impl<'inner, Context, Inspector> Buffer for Inspect<'inner, Context, Inspector>
where
Inspector: FnMut(&FormatElement),
{
type Context = Context;
fn write_element(&mut self, element: FormatElement) -> FormatResult<()> {
(self.inspector)(&element);
self.inner.write_element(element)
}
fn elements(&self) -> &[FormatElement] {
self.inner.elements()
}
fn state(&self) -> &FormatState<Self::Context> {
self.inner.state()
}
fn state_mut(&mut self) -> &mut FormatState<Self::Context> {
self.inner.state_mut()
}
fn snapshot(&self) -> BufferSnapshot {
self.inner.snapshot()
}
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
self.inner.restore_snapshot(snapshot)
}
}
pub struct RemoveSoftLinesBuffer<'a, Context> {
inner: &'a mut dyn Buffer<Context = Context>,
interned_cache: FxHashMap<Interned, Interned>,
is_in_expanded_conditional_content: bool,
}
impl<'a, Context> RemoveSoftLinesBuffer<'a, Context> {
pub fn new(inner: &'a mut dyn Buffer<Context = Context>) -> Self {
Self {
inner,
interned_cache: FxHashMap::default(),
is_in_expanded_conditional_content: false,
}
}
fn clean_interned(&mut self, interned: &Interned) -> Interned {
clean_interned(interned, &mut self.interned_cache)
}
}
fn clean_interned(
interned: &Interned,
interned_cache: &mut FxHashMap<Interned, Interned>,
) -> Interned {
match interned_cache.get(interned) {
Some(cleaned) => cleaned.clone(),
None => {
let result = interned
.iter()
.enumerate()
.find_map(|(index, element)| match element {
FormatElement::Line(LineMode::Soft | LineMode::SoftOrSpace) => {
let mut cleaned = Vec::new();
cleaned.extend_from_slice(&interned[..index]);
Some((cleaned, &interned[index..]))
}
FormatElement::Tag(Tag::StartConditionalContent(condition))
if condition.mode == PrintMode::Expanded =>
{
let mut cleaned = Vec::new();
cleaned.extend_from_slice(&interned[..index]);
Some((cleaned, &interned[index..]))
}
FormatElement::Interned(inner) => {
let cleaned_inner = clean_interned(inner, interned_cache);
if &cleaned_inner != inner {
let mut cleaned = Vec::with_capacity(interned.len());
cleaned.extend_from_slice(&interned[..index]);
cleaned.push(FormatElement::Interned(cleaned_inner));
Some((cleaned, &interned[index + 1..]))
} else {
None
}
}
_ => None,
});
let result = match result {
Some((mut cleaned, rest)) => {
let mut is_in_expanded_conditional_content = false;
for element in rest {
let element = match element {
FormatElement::Tag(Tag::StartConditionalContent(condition))
if condition.mode == PrintMode::Expanded =>
{
is_in_expanded_conditional_content = true;
continue;
}
FormatElement::Tag(Tag::EndConditionalContent)
if is_in_expanded_conditional_content =>
{
is_in_expanded_conditional_content = false;
continue;
}
_ if is_in_expanded_conditional_content => continue,
FormatElement::Line(LineMode::Soft) => continue,
FormatElement::Line(LineMode::SoftOrSpace) => FormatElement::Space,
FormatElement::Interned(interned) => {
FormatElement::Interned(clean_interned(interned, interned_cache))
}
element => element.clone(),
};
cleaned.push(element)
}
Interned::new(cleaned)
}
None => interned.clone(),
};
interned_cache.insert(interned.clone(), result.clone());
result
}
}
}
impl<Context> Buffer for RemoveSoftLinesBuffer<'_, Context> {
type Context = Context;
fn write_element(&mut self, element: FormatElement) -> FormatResult<()> {
let element = match element {
FormatElement::Tag(Tag::StartConditionalContent(condition)) => {
match condition.mode {
PrintMode::Expanded => {
self.is_in_expanded_conditional_content = true;
return Ok(());
}
PrintMode::Flat => {
return Ok(());
}
}
}
FormatElement::Tag(Tag::EndConditionalContent) => {
self.is_in_expanded_conditional_content = false;
return Ok(());
}
_ if self.is_in_expanded_conditional_content => return Ok(()),
FormatElement::Line(LineMode::Soft) => return Ok(()),
FormatElement::Line(LineMode::SoftOrSpace) => FormatElement::Space,
FormatElement::Interned(interned) => {
FormatElement::Interned(self.clean_interned(&interned))
}
element => element,
};
self.inner.write_element(element)
}
fn elements(&self) -> &[FormatElement] {
self.inner.elements()
}
fn state(&self) -> &FormatState<Self::Context> {
self.inner.state()
}
fn state_mut(&mut self) -> &mut FormatState<Self::Context> {
self.inner.state_mut()
}
fn snapshot(&self) -> BufferSnapshot {
self.inner.snapshot()
}
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
self.inner.restore_snapshot(snapshot)
}
}
pub trait BufferExtensions: Buffer + Sized {
#[must_use]
fn inspect<F>(&mut self, inspector: F) -> Inspect<Self::Context, F>
where
F: FnMut(&FormatElement),
{
Inspect::new(self, inspector)
}
#[must_use]
fn start_recording(&mut self) -> Recording<Self> {
Recording::new(self)
}
fn write_elements<I>(&mut self, elements: I) -> FormatResult<()>
where
I: IntoIterator<Item = FormatElement>,
{
for element in elements {
self.write_element(element)?;
}
Ok(())
}
}
impl<T> BufferExtensions for T where T: Buffer {}
#[derive(Debug)]
pub struct Recording<'buf, Buffer> {
start: usize,
buffer: &'buf mut Buffer,
}
impl<'buf, B> Recording<'buf, B>
where
B: Buffer,
{
fn new(buffer: &'buf mut B) -> Self {
Self {
start: buffer.elements().len(),
buffer,
}
}
#[inline(always)]
pub fn write_fmt(&mut self, arguments: Arguments<B::Context>) -> FormatResult<()> {
self.buffer.write_fmt(arguments)
}
#[inline(always)]
pub fn write_element(&mut self, element: FormatElement) -> FormatResult<()> {
self.buffer.write_element(element)
}
pub fn stop(self) -> Recorded<'buf> {
let buffer: &'buf B = self.buffer;
let elements = buffer.elements();
let recorded = if self.start > elements.len() {
&[]
} else {
&elements[self.start..]
};
Recorded(recorded)
}
}
#[derive(Debug, Copy, Clone)]
pub struct Recorded<'a>(&'a [FormatElement]);
impl Deref for Recorded<'_> {
type Target = [FormatElement];
fn deref(&self) -> &Self::Target {
self.0
}
}