Skip to content

Commit

Permalink
Added improved support for bytes (#616)
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko authored Oct 26, 2024
1 parent 36f0a53 commit 45eafaf
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ All notable changes to MiniJinja are documented here.
- Fixed an issue where CBOR was not correctly deserialized in
`minijinja-cli`. #611
- Added a `lines` filter to split a string into lines.
- Bytes are now better supported in MiniJinja. They can be created from
`Value::from_bytes` without having to go via serde, and they are now
producing a nicer looking debug output. #616

## 2.4.0

Expand Down
26 changes: 25 additions & 1 deletion minijinja/src/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,17 @@ impl fmt::Debug for ValueRepr {
ValueRepr::I128(val) => fmt::Debug::fmt(&{ val.0 }, f),
ValueRepr::String(val, _) => fmt::Debug::fmt(val, f),
ValueRepr::SmallStr(val) => fmt::Debug::fmt(val.as_str(), f),
ValueRepr::Bytes(val) => fmt::Debug::fmt(val, f),
ValueRepr::Bytes(val) => {
write!(f, "b'")?;
for &b in val.iter() {
if b == b'"' {
write!(f, "\"")?
} else {
write!(f, "{}", b.escape_ascii())?;
}
}
write!(f, "'")
}
ValueRepr::Object(val) => val.render(f),
}
}
Expand Down Expand Up @@ -745,6 +755,20 @@ impl Value {
ValueRepr::String(Arc::from(value), StringType::Safe).into()
}

/// Creates a value from a byte vector.
///
/// MiniJinja can hold on to bytes and has some limited built-in support for
/// working with them. They are non iterable and not particularly useful
/// in the context of templates. When they are stringified, they are assumed
/// to contain UTF-8 and will be treated as such. They become more useful
/// when a filter can do something with them (eg: base64 encode them etc.).
///
/// This method exists so that a value can be constructed as creating a
/// value from a `Vec<u8>` would normally just create a sequence.
pub fn from_bytes(value: Vec<u8>) -> Value {
ValueRepr::Bytes(value.into()).into()
}

/// Creates a value from a dynamic object.
///
/// For more information see [`Object`].
Expand Down
22 changes: 21 additions & 1 deletion minijinja/tests/test_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::sync::Arc;
use insta::{assert_debug_snapshot, assert_snapshot};
use similar_asserts::assert_eq;

use minijinja::value::{DynObject, Enumerator, Kwargs, Object, ObjectRepr, Rest, Value};
use minijinja::value::{DynObject, Enumerator, Kwargs, Object, ObjectRepr, Rest, Value, ValueKind};
use minijinja::{args, context, render, Environment, Error, ErrorKind};

#[test]
Expand Down Expand Up @@ -1187,3 +1187,23 @@ fn test_sorting() {
]
"###);
}

#[test]
fn test_bytes() {
let bytes = vec![1u8, 2, 3, 4];
let byte_value = Value::from_bytes(bytes);
assert_eq!(byte_value.kind(), ValueKind::Bytes);
assert!(byte_value.try_iter().is_err());
assert_eq!(format!("{:?}", byte_value), "b'\\x01\\x02\\x03\\x04'");

let bytes = vec![1u8, 2, 3, 4];
let not_byte_value = Value::from(bytes);
assert_eq!(not_byte_value.kind(), ValueKind::Seq);
assert!(not_byte_value.try_iter().is_ok());
assert_eq!(format!("{:?}", not_byte_value), "[1, 2, 3, 4]");

assert_eq!(
format!("{:?}", Value::from_bytes((&b"'foo\""[..]).into())),
"b'\\'foo\"'"
);
}

0 comments on commit 45eafaf

Please sign in to comment.