mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-02 15:25:19 +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::ops::Deref;
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
|
|
||||||
use super::MAX_LEN;
|
|
||||||
use super::escape::HtmlSafeOutput;
|
use super::escape::HtmlSafeOutput;
|
||||||
use crate::{FastWritable, Result};
|
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> {
|
impl<S: fmt::Display, I: AsIndent> fmt::Display for Indent<S, I> {
|
||||||
fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let indent = self.indent.as_indent();
|
let indent = self.indent.as_indent();
|
||||||
if indent.len() >= MAX_LEN || indent.is_empty() {
|
write!(
|
||||||
write!(dest, "{}", self.source)
|
IndentWriter::new(dest, indent, self.first, self.blank),
|
||||||
} else {
|
"{}",
|
||||||
let mut buffer;
|
self.source
|
||||||
let buffer = try_to_str!(self.source => buffer);
|
)?;
|
||||||
flush_indent(dest, indent, buffer, self.first, self.blank)
|
Ok(())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,34 +594,51 @@ impl<S: FastWritable, I: AsIndent> FastWritable for Indent<S, I> {
|
|||||||
values: &dyn crate::Values,
|
values: &dyn crate::Values,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let indent = self.indent.as_indent();
|
let indent = self.indent.as_indent();
|
||||||
if indent.len() >= MAX_LEN || indent.is_empty() {
|
self.source.write_into(
|
||||||
self.source.write_into(dest, values)
|
&mut IndentWriter::new(dest, indent, self.first, self.blank),
|
||||||
} else {
|
values,
|
||||||
let mut buffer = String::new();
|
)?;
|
||||||
self.source.write_into(&mut buffer, values)?;
|
Ok(())
|
||||||
Ok(flush_indent(dest, indent, &buffer, self.first, self.blank)?)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
impl<W: fmt::Write> fmt::Write for IndentWriter<'_, W> {
|
||||||
dest: &mut (impl fmt::Write + ?Sized),
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
indent: &str,
|
if self.indent.is_empty() {
|
||||||
s: &str,
|
return self.dest.write_str(s);
|
||||||
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)?;
|
|
||||||
}
|
}
|
||||||
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.
|
/// 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"
|
"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