mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-30 14:31:36 +00:00
book: add page about FastWritable
This commit is contained in:
parent
7881bc131b
commit
94fddd4df5
@ -24,6 +24,27 @@ monomorphised code. On average, expect `.to_string()` to be 100% to 200% slower
|
||||
[`.to_string()`]: <https://doc.rust-lang.org/stable/std/string/trait.ToString.html#tymethod.to_string>
|
||||
[`format!()`]: <https://doc.rust-lang.org/stable/std/fmt/fn.format.html>
|
||||
|
||||
## Faster Rendering of Custom Types
|
||||
|
||||
Every type that implements [`fmt::Display`] can be used in askama expressions: `{{ value }}`.
|
||||
Rendering with `fmt::Display` can be slow, though, because it uses [dynamic methods calls] in its
|
||||
[`fmt::Formatter`] argument. To speed up rendering (by a lot, actually),
|
||||
askama adds the trait [`FastWritable`]. For any custom type you want to render,
|
||||
it has to implement `fmt::Display`, but if it also implements `FastWritable`,
|
||||
then – using [autoref-based specialization] – the latter implementation is automatically preferred.
|
||||
|
||||
To reduce the amount of code duplication, you can let your `fmt::Display` implementation call
|
||||
your `FastWritable` implementation:
|
||||
|
||||
```rust
|
||||
{{#include ../../testing/tests/book_example_performance_fmt_call_fast_writable.rs}}
|
||||
```
|
||||
|
||||
[`fmt::Display`]: <https://doc.rust-lang.org/stable/std/fmt/trait.Display.html>
|
||||
[`fmt::Formatter`]: <https://doc.rust-lang.org/stable/std/fmt/struct.Formatter.html>
|
||||
[`FastWritable`]: <./doc/askama/filters/trait.FastWritable.html>
|
||||
[autoref-based specialization]: <https://lukaskalbertodt.github.io/2019/12/05/generalized-autoref-based-specialization.html>
|
||||
|
||||
## Slow Debug Recompilations
|
||||
|
||||
If you experience slow compile times when iterating with lots of templates,
|
||||
|
@ -0,0 +1,52 @@
|
||||
use std::fmt::{self, Write};
|
||||
|
||||
use askama::NO_VALUES;
|
||||
use askama::filters::FastWritable;
|
||||
|
||||
// In a real application, please have a look at
|
||||
// https://github.com/kdeldycke/awesome-falsehood/blob/690a070/readme.md#human-identity
|
||||
struct Name<'a> {
|
||||
forename: &'a str,
|
||||
surname: &'a str,
|
||||
}
|
||||
|
||||
impl fmt::Display for Name<'_> {
|
||||
// Because the method simply forwards the call, it should be `inline`.
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// `fmt::Write` has no access to runtime values,
|
||||
// so simply pass `NO_VALUES`.
|
||||
self.write_into(f, NO_VALUES)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FastWritable for Name<'_> {
|
||||
fn write_into<W: fmt::Write + ?Sized>(
|
||||
&self,
|
||||
dest: &mut W,
|
||||
_values: &dyn askama::Values,
|
||||
) -> askama::Result<()> {
|
||||
dest.write_str(self.surname)?;
|
||||
dest.write_str(", ")?;
|
||||
dest.write_str(self.forename)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn both_implementations_should_render_the_same_text() {
|
||||
let person = Name {
|
||||
forename: "Max",
|
||||
surname: "Mustermann",
|
||||
};
|
||||
|
||||
let mut buf_fmt = String::new();
|
||||
write!(buf_fmt, "{person}").unwrap();
|
||||
|
||||
let mut buf_fast = String::new();
|
||||
person.write_into(&mut buf_fast, NO_VALUES).unwrap();
|
||||
|
||||
assert_eq!(buf_fmt, buf_fast);
|
||||
assert_eq!(buf_fmt, "Mustermann, Max");
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user