1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-08-04 18:42:14 +03:00
Files
2024-05-02 14:04:14 +02:00

106 lines
4.0 KiB
Rust

// Copyright 2021 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// Count the number of tokens. Used to have a fixed-sized array for the
/// templates list.
macro_rules! count {
() => (0_usize);
( $x:tt $($xs:tt)* ) => (1_usize + count!($($xs)*));
}
/// Macro that helps generating helper function that renders a specific template
/// with a strongly-typed context. It also register the template in a static
/// array to help detecting missing templates at startup time.
///
/// The syntax looks almost like a function to confuse syntax highlighter as
/// little as possible.
#[macro_export]
macro_rules! register_templates {
{
$(
extra = { $( $extra_template:expr ),* $(,)? };
)?
$(
// Match any attribute on the function, such as #[doc], #[allow(dead_code)], etc.
$( #[ $attr:meta ] )*
// The function name
pub fn $name:ident
// Optional list of generics. Taken from
// https://newbedev.com/rust-macro-accepting-type-with-generic-parameters
$(< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)?
// Type of context taken by the template
( $param:ty )
{
// The name of the template file
$template:expr
}
)*
} => {
/// List of registered templates
static TEMPLATES: [&'static str; count!( $( $template )* )] = [ $( $template, )* ];
impl Templates {
$(
$(#[$attr])?
///
/// # Errors
///
/// Returns an error if the template fails to render.
pub fn $name
$(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?
(&self, context: &$param)
-> Result<String, TemplateError> {
let ctx = ::minijinja::value::Value::from_serialize(context);
let env = self.environment.load();
let tmpl = env.get_template($template)
.map_err(|source| TemplateError::Missing { template: $template, source })?;
tmpl.render(ctx)
.map_err(|source| TemplateError::Render { template: $template, source })
}
)*
}
/// Helps rendering each template with sample data
pub mod check {
use super::*;
$(
#[doc = concat!("Render the `", $template, "` template with sample contexts")]
///
/// # Errors
///
/// Returns an error if the template fails to render with any of the sample.
pub fn $name
$(< $( $lt $( : $clt $(+ $dlt )* + TemplateContext )? ),+ >)?
(templates: &Templates, now: chrono::DateTime<chrono::Utc>, rng: &mut impl rand::Rng)
-> anyhow::Result<()> {
let samples: Vec< $param > = TemplateContext::sample(now, rng);
let name = $template;
for sample in samples {
let context = serde_json::to_value(&sample)?;
::tracing::info!(name, %context, "Rendering template");
templates. $name (&sample)
.with_context(|| format!("Failed to render template {:?} with context {}", name, context))?;
}
Ok(())
}
)*
}
};
}