Relax rules for filesizeformat filter

Remove `humansize` dependency
This commit is contained in:
Guillaume Gomez 2024-10-31 22:12:44 +01:00
parent ab88dc756c
commit c87be3ec36
11 changed files with 74 additions and 32 deletions

View File

@ -21,11 +21,10 @@ rustdoc-args = ["--generate-link-to-definition", "--cfg=docsrs"]
maintenance = { status = "actively-developed" }
[features]
default = ["config", "humansize", "urlencode"]
default = ["config", "urlencode"]
full = ["default", "code-in-doc", "serde_json"]
code-in-doc = ["rinja_derive/code-in-doc"]
config = ["rinja_derive/config"]
humansize = ["rinja_derive/humansize", "dep:humansize"]
serde_json = ["rinja_derive/serde_json", "dep:serde", "dep:serde_json"]
urlencode = ["rinja_derive/urlencode", "dep:percent-encoding"]
@ -39,7 +38,6 @@ with-warp = ["rinja_derive/with-warp"]
[dependencies]
rinja_derive = { version = "=0.3.5", path = "../rinja_derive" }
humansize = { version = "2", optional = true }
num-traits = { version = "0.2.6", optional = true }
percent-encoding = { version = "2.1.0", optional = true }
serde = { version = "1.0", optional = true }

View File

@ -1,8 +1,6 @@
use std::convert::Infallible;
use std::fmt;
use humansize::{DECIMAL, ISizeFormatter, ToF64};
/// Returns adequate string representation (in KB, ..) of number of bytes
///
/// ## Example
@ -21,24 +19,69 @@ use humansize::{DECIMAL, ISizeFormatter, ToF64};
/// assert_eq!(tmpl.to_string(), "Filesize: 1.23 MB.");
/// ```
#[inline]
pub fn filesizeformat(b: &impl ToF64) -> Result<FilesizeFormatFilter, Infallible> {
Ok(FilesizeFormatFilter(b.to_f64()))
pub fn filesizeformat(b: f32) -> Result<FilesizeFormatFilter, Infallible> {
Ok(FilesizeFormatFilter(b))
}
#[derive(Debug, Clone, Copy)]
pub struct FilesizeFormatFilter(f64);
pub struct FilesizeFormatFilter(f32);
struct NbAndDecimal(u32);
impl NbAndDecimal {
fn new(nb: f32) -> Self {
// `nb` will never be bigger than 999_999 so we're fine with usize.
Self(nb as _)
}
}
impl fmt::Display for NbAndDecimal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let sub = self.0 % 1_000 / 10;
if sub != 0 {
if sub < 10 {
f.write_fmt(format_args!("{}.0{sub}", self.0 / 1_000))
} else {
f.write_fmt(format_args!("{}.{sub}", self.0 / 1_000))
}
} else {
f.write_fmt(format_args!("{}", self.0 / 1_000))
}
}
}
impl fmt::Display for FilesizeFormatFilter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("{}", ISizeFormatter::new(self.0, &DECIMAL)))
if self.0 < 1e3 {
return f.write_fmt(format_args!("{} B", self.0));
}
for (unit, max, divider) in [
(" KB", 1e6, 1.),
(" MB", 1e9, 1e3),
(" GB", 1e12, 1e6),
(" TB", 1e15, 1e9),
(" PB", 1e18, 1e12),
(" EB", 1e21, 1e15),
(" ZB", 1e24, 1e18),
] {
if self.0 < max {
f.write_fmt(format_args!("{}", NbAndDecimal::new(self.0 / divider)))?;
return f.write_str(unit);
}
}
f.write_fmt(format_args!("{} YB", NbAndDecimal::new(self.0 / 1e21)))
}
}
#[test]
#[allow(clippy::needless_borrows_for_generic_args)]
fn test_filesizeformat() {
assert_eq!(filesizeformat(&0).unwrap().to_string(), "0 B");
assert_eq!(filesizeformat(&999u64).unwrap().to_string(), "999 B");
assert_eq!(filesizeformat(&1000i32).unwrap().to_string(), "1 kB");
assert_eq!(filesizeformat(&1023).unwrap().to_string(), "1.02 kB");
assert_eq!(filesizeformat(&1024usize).unwrap().to_string(), "1.02 kB");
assert_eq!(filesizeformat(0.).unwrap().to_string(), "0 B");
assert_eq!(filesizeformat(999.).unwrap().to_string(), "999 B");
assert_eq!(filesizeformat(1000.).unwrap().to_string(), "1 KB");
assert_eq!(filesizeformat(1023.).unwrap().to_string(), "1.02 KB");
assert_eq!(filesizeformat(1024.).unwrap().to_string(), "1.02 KB");
assert_eq!(filesizeformat(9_499_014.).unwrap().to_string(), "9.49 MB");
assert_eq!(
filesizeformat(954_548_589.2).unwrap().to_string(),
"954.54 MB"
);
}

View File

@ -12,7 +12,6 @@
mod builtin;
mod escape;
#[cfg(feature = "humansize")]
mod humansize;
#[cfg(feature = "serde_json")]
mod json;
@ -27,7 +26,6 @@ pub use self::escape::{
AutoEscape, AutoEscaper, Escaper, FastWritable, Html, HtmlSafe, HtmlSafeOutput, MaybeSafe,
Safe, Text, Unsafe, Writable, WriteWritable, e, escape, safe,
};
#[cfg(feature = "humansize")]
pub use self::humansize::filesizeformat;
#[cfg(feature = "serde_json")]
pub use self::json::{AsIndent, json, json_pretty};

View File

@ -24,7 +24,6 @@ default = ["rinja/default"]
full = ["rinja/full"]
code-in-doc = ["rinja/code-in-doc"]
config = ["rinja/config"]
humansize = ["rinja/humansize"]
serde_json = ["rinja/serde_json"]
urlencode = ["rinja/urlencode"]

View File

@ -24,7 +24,6 @@ default = ["rinja/default"]
full = ["rinja/full"]
code-in-doc = ["rinja/code-in-doc"]
config = ["rinja/config"]
humansize = ["rinja/humansize"]
serde_json = ["rinja/serde_json"]
urlencode = ["rinja/urlencode"]

View File

@ -20,7 +20,6 @@ proc-macro = true
[features]
code-in-doc = ["dep:pulldown-cmark"]
config = ["dep:serde", "dep:basic-toml", "parser/config"]
humansize = []
urlencode = []
serde_json = []
with-actix-web = []

View File

@ -1657,21 +1657,15 @@ impl<'a> Generator<'a> {
buf: &mut Buffer,
name: &str,
args: &[WithSpan<'_, Expr<'_>>],
node: &WithSpan<'_, T>,
_node: &WithSpan<'_, T>,
) -> Result<DisplayWrap, CompileError> {
if cfg!(not(feature = "humansize")) {
return Err(ctx.generate_error(
&format!("the `{name}` filter requires the `humansize` feature to be enabled"),
node,
));
}
// All filters return numbers, and any default formatted number is HTML safe.
buf.write(format_args!(
"rinja::filters::HtmlSafeOutput(rinja::filters::{name}(",
"rinja::filters::HtmlSafeOutput(rinja::filters::{name}(\
rinja::helpers::get_primitive_value(&("
));
self._visit_args(ctx, buf, args)?;
buf.write(")?)");
buf.write(")) as rinja::helpers::core::primitive::f32)?)");
Ok(DisplayWrap::Unwrapped)
}

View File

@ -23,7 +23,6 @@ __standalone = []
code-in-doc = ["dep:pulldown-cmark"]
config = ["dep:serde", "dep:basic-toml", "parser/config"]
humansize = []
urlencode = []
serde_json = []
with-actix-web = []

View File

@ -24,7 +24,6 @@ default = ["rinja/default"]
full = ["rinja/full"]
code-in-doc = ["rinja/code-in-doc"]
config = ["rinja/config"]
humansize = ["rinja/humansize"]
serde_json = ["rinja/serde_json"]
urlencode = ["rinja/urlencode"]

View File

@ -24,7 +24,6 @@ default = ["rinja/default"]
full = ["rinja/full"]
code-in-doc = ["rinja/code-in-doc"]
config = ["rinja/config"]
humansize = ["rinja/humansize"]
serde_json = ["rinja/serde_json"]
urlencode = ["rinja/urlencode"]

View File

@ -427,3 +427,18 @@ fn test_linebreaks() {
"<p>&#60;script&#62;<br/>alert(&#39;Hello, world!&#39;)<br/>&#60;/script&#62;</p>",
);
}
// Regression tests for <https://github.com/rinja-rs/rinja/issues/215>.
#[test]
fn test_filesizeformat() {
#[derive(Template)]
#[template(
source = r#"{% if let Some(x) = s %}{{x|filesizeformat}}{% endif %}"#,
ext = "html"
)]
struct S {
s: Option<u32>,
}
assert_eq!(S { s: Some(12) }.render().unwrap(), "12 B");
}