This repository has been archived on 2026-08-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
donglora/vendor/minijinja/src/macros.rs
T
swaitsandClaude Opus 4.6 3102fc747a feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support:
- Splash screen on boot (1.5s) with project name, version, board
- Dashboard showing radio state, config, counters, RSSI/SNR
- RSSI history sparkline (64-sample ring buffer, 2px-wide bars)
- DisplayOn/DisplayOff host commands routed via dedicated channel
- Pure render functions against generic DrawTarget (no hardware coupling)
- Display on/off control bypasses radio task entirely

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 20:42:54 -06:00

327 lines
10 KiB
Rust

// `ok!` and `some!` are less bloaty alternatives to the standard library's try operator (`?`).
// Since we do not need type conversions in this crate we can fall back to much easier match
// patterns that compile faster and produce less bloaty code.
macro_rules! ok {
($expr:expr) => {
match $expr {
Ok(val) => val,
Err(err) => return Err(err),
}
};
}
macro_rules! some {
($expr:expr) => {
match $expr {
Some(val) => val,
None => return None,
}
};
}
/// Hidden utility module for the [`context!`](crate::context!) macro.
#[doc(hidden)]
pub mod __context {
use crate::value::Value;
use crate::Environment;
use std::collections::BTreeMap;
use std::rc::Rc;
#[inline(always)]
pub fn make() -> BTreeMap<&'static str, Value> {
BTreeMap::default()
}
#[inline(always)]
pub fn add(ctx: &mut BTreeMap<&'static str, Value>, key: &'static str, value: Value) {
ctx.insert(key, value);
}
#[inline(always)]
pub fn build(ctx: BTreeMap<&'static str, Value>) -> Value {
Value::from_object(ctx)
}
pub fn thread_local_env() -> Rc<Environment<'static>> {
thread_local! {
static ENV: Rc<Environment<'static>> = Rc::new(Environment::new());
}
ENV.with(|x| x.clone())
}
}
/// Creates a template context from keys and values or merging in another value.
///
/// ```rust
/// # use minijinja::context;
/// let ctx = context!{
/// name => "Peter",
/// location => "World",
/// };
/// ```
///
/// Alternatively if the variable name matches the key name it can
/// be omitted:
///
/// ```rust
/// # use minijinja::context;
/// let name = "Peter";
/// let ctx = context!{ name };
/// ```
///
/// The return value is a [`Value`](crate::value::Value).
///
/// Note that [`context!`](crate::context!) can also be used recursively if you need to
/// create nested objects:
///
/// ```rust
/// # use minijinja::context;
/// let ctx = context! {
/// nav => vec![
/// context!(path => "/", title => "Index"),
/// context!(path => "/downloads", title => "Downloads"),
/// context!(path => "/faq", title => "FAQ"),
/// ]
/// };
/// ```
///
/// Additionally the macro supports a second syntax that can merge other
/// contexts or values. In that case one or more values need to be
/// passed with a leading `..` operator. This is useful to supply extra
/// values into render in a common place. The order of precedence is
/// left to right:
///
/// ```rust
/// # use minijinja::context;
/// let ctx = context! { a => "A" };
/// let ctx = context! { ..ctx, ..context! {
/// b => "B"
/// }};
///
/// // or
///
/// let ctx = context! {
/// a => "A",
/// ..context! {
/// b => "B"
/// }
/// };
/// ```
///
/// The merge works with an value, not just values created by the `context!`
/// macro and is performed lazy. This means it also works with dynamic
/// [`Object`](crate::value::Object)s. The merge uses the underlying
/// [`merge_maps`](crate::value::merge_maps) function.
///
/// # Note on Conversions
///
/// This macro uses [`Value::from_serialize`](crate::Value::from_serialize)
/// for conversions.
///
/// This macro currently does not move passed values. Future versions of
/// MiniJinja are going to change the move behavior and it's recommended to not
/// depend on this implicit reference behavior. You should thus pass values
/// with `&value` if you intend on still being able to reference them
/// after the macro invocation.
#[macro_export]
macro_rules! context {
() => {
$crate::__context::build($crate::__context::make())
};
(
$($key:ident $(=> $value:expr)?),*
$(, .. $ctx:expr),* $(,)?
) => {{
let mut ctx = $crate::__context::make();
$(
$crate::__context_pair!(ctx, $key $(=> $value)?);
)*
let ctx = $crate::__context::build(ctx);
let merge_ctx = [
$(
$crate::value::Value::from($ctx),
)*
];
if merge_ctx.is_empty() {
ctx
} else {
$crate::value::merge_maps(
merge_ctx.into_iter().rev().chain(::std::iter::once(ctx)))
}
}};
(
$(.. $ctx:expr),* $(,)?
) => {{
$crate::value::merge_maps([
$(
$crate::value::Value::from($ctx),
)*
].into_iter().rev())
}};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __context_pair {
($ctx:ident, $key:ident) => {{
$crate::__context_pair!($ctx, $key => $key);
}};
($ctx:ident, $key:ident => $value:literal) => {
$crate::__context::add(&mut $ctx, stringify!($key), $crate::value::Value::from($value));
};
($ctx:ident, $key:ident => context! { $($inner:tt)* }) => {
$crate::__context::add(&mut $ctx, stringify!($key), $crate::context! { $($inner)* });
};
($ctx:ident, $key:ident => context!($($inner:tt)*)) => {
$crate::__context::add(&mut $ctx, stringify!($key), $crate::context!($($inner)*));
};
($ctx:ident, $key:ident => $value:expr) => {
$crate::__context::add(
&mut $ctx,
stringify!($key),
$crate::value::Value::from_serialize(&$value),
);
};
}
/// An utility macro to create arguments for function calls.
///
/// This creates a slice of values on the stack which can be
/// passed to [`call`](crate::value::Value::call),
/// [`call_method`](crate::value::Value::call_method),
/// [`apply_filter`](crate::State::apply_filter),
/// [`perform_test`](crate::State::perform_test) or similar
/// APIs that take slices of values.
///
/// It supports both positional and keyword arguments.
/// To mark a parameter as keyword argument define it as
/// `name => value`, otherwise just use `value`.
///
/// ```
/// # use minijinja::{value::Value, args, Environment};
/// # let env = Environment::default();
/// # let state = &env.empty_state();
/// # let value = Value::from(());
/// value.call(state, args!(1, 2, foo => "bar"));
/// ```
///
/// Note that this like [`context!`](crate::context) goes through
/// [`Value::from_serialize`](crate::value::Value::from_serialize).
#[macro_export]
macro_rules! args {
() => { &[][..] as &[$crate::value::Value] };
($($arg:tt)*) => { $crate::__args_helper!(branch [[$($arg)*]], [$($arg)*]) };
}
/// Utility macro for `args!`
#[macro_export]
#[doc(hidden)]
macro_rules! __args_helper {
// branch helper between `args` and `kwargs`.
//
// It analyzes the first bracket enclosed tt bundle to see if kwargs are
// used. If yes, it uses `kwargs` to handle the second tt
// bundle, otherwise it uses `args`.
(branch [[]], $args:tt) => { $crate::__args_helper!(args $args) };
(branch [[$n:ident => $e:expr]], $args:tt) => { $crate::__args_helper!(kwargs $args) };
(branch [[$n:ident => $e:expr, $($r:tt)*]], $args:tt) => { $crate::__args_helper!(kwargs $args) };
(branch [[$e:expr]], $args:tt) => { $crate::__args_helper!(args $args) };
(branch [[$e:expr, $($rest:tt)*]], $args:tt) => { $crate::__args_helper!(branch [[$($rest)*]], $args) };
// creates args on the stack
(args [$($arg:tt)*]) => {&{
let mut args = Vec::<$crate::value::Value>::new();
$crate::__args_helper!(peel args, args, false, [$($arg)*]);
args
}[..]};
// creates args with kwargs on the stack
(kwargs [$($arg:tt)*]) => {&{
let mut args = Vec::<$crate::value::Value>::new();
let mut kwargs = Vec::<(&str, $crate::value::Value)>::new();
$crate::__args_helper!(peel args, kwargs, false, [$($arg)*]);
args.push($crate::value::Kwargs::from_iter(kwargs.into_iter()).into());
args
}[..]};
// Peels a single argument from the arguments and stuffs them into
// `$args` or `$kwargs` depending on type.
(peel $args:ident, $kwargs:ident, $has_kwargs:ident, []) => {};
(peel $args:ident, $kwargs:ident, $has_kwargs:ident, [$name:ident => $expr:expr]) => {
$kwargs.push((stringify!($name), $crate::value::Value::from_serialize(&$expr)));
};
(peel $args:ident, $kwargs:ident, $has_kwargs:ident, [$name:ident => $expr:expr, $($rest:tt)*]) => {
$kwargs.push((stringify!($name), $crate::value::Value::from_serialize(&$expr)));
$crate::__args_helper!(peel $args, $kwargs, true, [$($rest)*]);
};
(peel $args:ident, $kwargs:ident, false, [$expr:expr]) => {
$args.push($crate::value::Value::from_serialize(&$expr));
};
(peel $args:ident, $kwargs:ident, false, [$expr:expr, $($rest:tt)*]) => {
$args.push($crate::value::Value::from_serialize(&$expr));
$crate::__args_helper!(peel $args, $kwargs, false, [$($rest)*]);
};
}
/// A macro similar to [`format!`] but that uses MiniJinja for rendering.
///
/// This can be used to quickly render a MiniJinja template into a string
/// without having to create an environment first which can be useful in
/// some situations. Note however that the template is re-parsed every
/// time the [`render!`](crate::render) macro is called which is potentially
/// slow.
///
/// There are two forms for this macro. The default form takes template
/// source and context variables, the extended form also lets you provide
/// a custom environment that should be used rather than a default one.
/// The context variables are passed the same way as with the
/// [`context!`](crate::context) macro.
///
/// # Example
///
/// Passing context explicitly:
///
/// ```
/// # use minijinja::render;
/// println!("{}", render!("Hello {{ name }}!", name => "World"));
/// ```
///
/// Passing variables with the default name:
///
/// ```
/// # use minijinja::render;
/// let name = "World";
/// println!("{}", render!("Hello {{ name }}!", name));
/// ```
///
/// Passing an explicit environment:
///
/// ```
/// # use minijinja::{Environment, render};
/// let env = Environment::new();
/// println!("{}", render!(in env, "Hello {{ name }}!", name => "World"));
/// ```
///
/// # Panics
///
/// This macro panics if the format string is an invalid template or the
/// template evaluation failed.
#[macro_export]
macro_rules! render {
(
in $env:expr,
$tmpl:expr
$(, $key:ident $(=> $value:expr)?)* $(,)?
) => {
($env).render_str($tmpl, $crate::context! { $($key $(=> $value)? ,)* })
.expect("failed to render expression")
};
(
$tmpl:expr
$(, $key:ident $(=> $value:expr)?)* $(,)?
) => {
$crate::render!(in $crate::__context::thread_local_env(), $tmpl, $($key $(=> $value)? ,)*)
}
}