mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-30 06:21:13 +00:00
Rewrite indent
filter to use IndentWriter
Refactored the `indent` filter implementation to introduce the `IndentWriter` struct, eliminating the need for memory allocation. Removed the `MAX_LEN` restriction and the `fuzzed_indent_filter` test, as they are no longer necessary with the new approach. Fixes #465.
This commit is contained in:
parent
08682a3133
commit
8c6d227ddb
@ -7,7 +7,6 @@ use core::fmt::{self, Write};
|
||||
use core::ops::Deref;
|
||||
use core::pin::Pin;
|
||||
|
||||
use super::MAX_LEN;
|
||||
use super::escape::HtmlSafeOutput;
|
||||
use crate::{FastWritable, Result};
|
||||
|
||||
@ -579,13 +578,12 @@ pub struct Indent<S, I> {
|
||||
impl<S: fmt::Display, I: AsIndent> fmt::Display for Indent<S, I> {
|
||||
fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let indent = self.indent.as_indent();
|
||||
if indent.len() >= MAX_LEN || indent.is_empty() {
|
||||
write!(dest, "{}", self.source)
|
||||
} else {
|
||||
let mut buffer;
|
||||
let buffer = try_to_str!(self.source => buffer);
|
||||
flush_indent(dest, indent, buffer, self.first, self.blank)
|
||||
}
|
||||
write!(
|
||||
IndentWriter::new(dest, indent, self.first, self.blank),
|
||||
"{}",
|
||||
self.source
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -596,34 +594,51 @@ impl<S: FastWritable, I: AsIndent> FastWritable for Indent<S, I> {
|
||||
values: &dyn crate::Values,
|
||||
) -> crate::Result<()> {
|
||||
let indent = self.indent.as_indent();
|
||||
if indent.len() >= MAX_LEN || indent.is_empty() {
|
||||
self.source.write_into(dest, values)
|
||||
} else {
|
||||
let mut buffer = String::new();
|
||||
self.source.write_into(&mut buffer, values)?;
|
||||
Ok(flush_indent(dest, indent, &buffer, self.first, self.blank)?)
|
||||
self.source.write_into(
|
||||
&mut IndentWriter::new(dest, indent, self.first, self.blank),
|
||||
values,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct IndentWriter<'a, W> {
|
||||
dest: W,
|
||||
indent: &'a str,
|
||||
first: bool,
|
||||
blank: bool,
|
||||
is_new_line: bool,
|
||||
}
|
||||
|
||||
impl<'a, W: fmt::Write> IndentWriter<'a, W> {
|
||||
fn new(dest: W, indent: &'a str, first: bool, blank: bool) -> Self {
|
||||
IndentWriter {
|
||||
dest,
|
||||
indent,
|
||||
first,
|
||||
blank,
|
||||
is_new_line: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flush_indent(
|
||||
dest: &mut (impl fmt::Write + ?Sized),
|
||||
indent: &str,
|
||||
s: &str,
|
||||
first: bool,
|
||||
blank: bool,
|
||||
) -> fmt::Result {
|
||||
if s.len() >= MAX_LEN {
|
||||
return dest.write_str(s);
|
||||
}
|
||||
|
||||
for (idx, line) in s.split_inclusive('\n').enumerate() {
|
||||
if (first || idx > 0) && (blank || !matches!(line, "\n" | "\r\n")) {
|
||||
dest.write_str(indent)?;
|
||||
impl<W: fmt::Write> fmt::Write for IndentWriter<'_, W> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
if self.indent.is_empty() {
|
||||
return self.dest.write_str(s);
|
||||
}
|
||||
dest.write_str(line)?;
|
||||
|
||||
for (idx, line) in s.split_inclusive('\n').enumerate() {
|
||||
if (self.first || idx > 0 || !self.is_new_line)
|
||||
&& (self.blank || !matches!(line, "\n" | "\r\n"))
|
||||
{
|
||||
self.dest.write_str(self.indent)?;
|
||||
}
|
||||
self.dest.write_str(line)?;
|
||||
self.is_new_line = line.ends_with('\n');
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Capitalize a value. The first character will be uppercase, all others lowercase.
|
||||
@ -1172,10 +1187,4 @@ mod tests {
|
||||
"Fo\x0bOo\x0cOo\u{2002}Oo\u{3000}Bar"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzzed_indent_filter() {
|
||||
let s = "hello\nfoo\nbar".to_string().repeat(1024);
|
||||
assert_eq!(indent(s.clone(), 4, false, false).unwrap().to_string(), s);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user