Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/cli_v2/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub(crate) mod value_vec;
84 changes: 84 additions & 0 deletions src/cli_v2/value_vec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use std::sync::{Arc, RwLock};

use minijinja::{ErrorKind, value::DynObject};

pub(crate) fn new_value_vec() -> DynObject {
DynObject::new(Arc::new(ValueVec(RwLock::new(vec![]))))
}

impl minijinja::value::Object for ValueVec {
fn repr(self: &Arc<Self>) -> minijinja::value::ObjectRepr {
minijinja::value::ObjectRepr::Iterable
}

fn call_method(
self: &Arc<Self>,
_state: &minijinja::State<'_, '_>,
method: &str,
args: &[minijinja::Value],
) -> Result<minijinja::Value, minijinja::Error> {
match method {
"push" => self.push(args),
_ => Err(minijinja::Error::new(
ErrorKind::UnknownMethod,
format!("Unexpected method {method}"),
)),
}
}

fn enumerate(self: &Arc<Self>) -> minijinja::value::Enumerator {
let vals = self
.0
.read()
.expect("Unable to read from ValueVec, RwLock was poisoned")
.iter()
.map(|s| s.to_owned())
.collect::<Vec<_>>();
minijinja::value::Enumerator::Iter(Box::new(vals.into_iter()))
}
}

/// List of `minijinja::Value`, a workaround for `minijinja`s mutability limitations.
///
/// Like `minijinja`s own `namespace`, but in array form instead of dict form.
#[derive(Debug)]
struct ValueVec(RwLock<Vec<minijinja::Value>>);

impl ValueVec {
fn push(
self: &Arc<Self>,
args: &[minijinja::Value],
) -> Result<minijinja::Value, minijinja::Error> {
ensure_n_args("push", 1, args)?;
{
let mut list = self
.0
.try_write()
.map_err(|e| minijinja::Error::new(ErrorKind::InvalidOperation, e.to_string()))?;
list.push(args[0].clone());
}
Ok(minijinja::Value::UNDEFINED)
}
}

fn ensure_n_args(
method: &str,
n: usize,
args: &[minijinja::Value],
) -> Result<(), minijinja::Error> {
let err = |kind| -> Result<(), minijinja::Error> {
Err(minijinja::Error::new(
kind,
format!(
"{method} | Expected: {n} args, got {} arguments",
args.len()
),
))
};

match args.len().cmp(&n) {
std::cmp::Ordering::Less => err(ErrorKind::MissingArgument),
std::cmp::Ordering::Greater => err(ErrorKind::TooManyArguments),
std::cmp::Ordering::Equal => Ok(()),
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod api;
mod cli_v1;
pub(crate) mod cli_v2;
mod codesamples;
mod generator;
mod postprocessing;
Expand Down
3 changes: 3 additions & 0 deletions src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ pub fn env_with_dir(
pub fn populate_env(
mut env: minijinja::Environment<'static>,
) -> Result<minijinja::Environment<'static>, minijinja::Error> {
// === Custom functions ===
env.add_function("vec", crate::cli_v2::value_vec::new_value_vec);

// === Custom filters ===

// --- Case conversion ---
Expand Down