Merge branch 'feature/json-filter'

This commit is contained in:
Kogia-sima 2020-12-18 12:24:43 +09:00
commit fe11aff782
8 changed files with 113 additions and 1 deletions

3
Cargo.lock generated
View File

@ -48,6 +48,7 @@ dependencies = [
"sailfish",
"sailfish-compiler",
"sailfish-macros",
"serde_json",
"trybuild",
]
@ -133,6 +134,8 @@ dependencies = [
"itoap",
"ryu",
"sailfish-macros",
"serde",
"serde_json",
"version_check",
]

View File

@ -6,9 +6,10 @@ edition = "2018"
publish = false
[dependencies]
sailfish = { path = "../../sailfish", default-features = false }
sailfish = { path = "../../sailfish", default-features = false, features = ["json"] }
sailfish-macros = { path = "../../sailfish-macros" }
sailfish-compiler = { path = "../../sailfish-compiler" }
serde_json = "1.0.53"
[dev-dependencies]
trybuild = "1.0.28"

View File

@ -0,0 +1,4 @@
{
"name": "JSON test",
"data": {"age":43,"name":"John Doe","phones":["+44 1234567","+44 2345678"]}
}

View File

@ -0,0 +1,4 @@
{
"name": "JSON test",
"data": <%- data | json %>
}

View File

@ -307,6 +307,25 @@ struct TruncateFilter;
fn test_truncate_filter() {
assert_render("truncate-filter", TruncateFilter);
}
#[derive(TemplateOnce)]
#[template(path = "json-filter.stpl")]
struct JsonFilter {
data: serde_json::Value,
}
#[test]
fn test_json_filter() {
let data = serde_json::json!({
"name": "John Doe",
"age": 43,
"phones": [
"+44 1234567",
"+44 2345678"
]
});
assert_render("json-filter", JsonFilter { data });
}
#[cfg(unix)]
mod unix {

View File

@ -15,11 +15,14 @@ edition = "2018"
[features]
default = ["derive", "perf-inline"]
derive = ["sailfish-macros"]
json = ["serde", "serde_json"]
perf-inline = []
[dependencies]
itoap = "0.1.0"
ryu = "1.0.4"
serde = { version = "1.0.111", optional = true }
serde_json = { version = "1.0.53", optional = true }
[dependencies.sailfish-macros]
path = "../sailfish-macros"

View File

@ -196,6 +196,74 @@ pub fn truncate<T: Render>(expr: &T, mut limit: usize) -> Truncate<T> {
Truncate(expr, limit)
}
cfg_json! {
pub struct Json<'a, T>(&'a T);
impl<'a, T: serde::Serialize> Render for Json<'a, T> {
#[inline]
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
struct Writer<'a>(&'a mut Buffer);
impl<'a> std::io::Write for Writer<'a> {
#[inline]
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let buf = unsafe { std::str::from_utf8_unchecked(buf) };
self.0.push_str(buf);
Ok(buf.len())
}
#[inline]
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
self.write(buf).map(|_| {})
}
#[inline]
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
serde_json::to_writer(Writer(b), self.0)
.map_err(|e| RenderError::new(&e.to_string()))
}
#[inline]
fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
use super::escape::escape_to_buf;
struct Writer<'a>(&'a mut Buffer);
impl<'a> std::io::Write for Writer<'a> {
#[inline]
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let buf = unsafe { std::str::from_utf8_unchecked(buf) };
escape_to_buf(buf, self.0);
Ok(buf.len())
}
#[inline]
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
self.write(buf).map(|_| {})
}
#[inline]
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
serde_json::to_writer(Writer(b), self.0)
.map_err(|e| RenderError::new(&e.to_string()))
}
}
/// Serialize the given data structure as JSON into the buffer
#[inline]
pub fn json<T: serde::Serialize>(expr: &T) -> Json<T> {
Json(expr)
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -1,5 +1,15 @@
use std::ptr;
macro_rules! cfg_json {
($($item:item)*) => {
$(
#[cfg(feature = "json")]
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
$item
)*
}
}
#[cfg(sailfish_nightly)]
macro_rules! likely {
($val:expr) => {