minijinja/value/
argtypes.rs

1use std::borrow::Cow;
2use std::cell::RefCell;
3use std::collections::HashSet;
4use std::ops::{Deref, DerefMut};
5use std::sync::Arc;
6
7use crate::error::{Error, ErrorKind};
8use crate::utils::UndefinedBehavior;
9use crate::value::{
10    DynObject, ObjectRepr, Packed, SmallStr, StringType, Value, ValueKind, ValueMap, ValueRepr,
11};
12use crate::vm::State;
13
14use super::{Enumerator, Object};
15
16/// A utility trait that represents the return value of functions and filters.
17///
18/// It's implemented for the following types:
19///
20/// * `Rv` where `Rv` implements `Into<AnyMapObject>`
21/// * `Result<Rv, Error>` where `Rv` implements `Into<Value>`
22///
23/// The equivalent for test functions is [`TestResult`](crate::tests::TestResult).
24pub trait FunctionResult {
25    #[doc(hidden)]
26    fn into_result(self) -> Result<Value, Error>;
27}
28
29impl<I: Into<Value>> FunctionResult for Result<I, Error> {
30    fn into_result(self) -> Result<Value, Error> {
31        self.map(Into::into)
32    }
33}
34
35impl<I: Into<Value>> FunctionResult for I {
36    fn into_result(self) -> Result<Value, Error> {
37        Ok(self.into())
38    }
39}
40
41/// Helper trait representing valid filter, test and function arguments.
42///
43/// Since it's more convenient to write filters and tests with concrete
44/// types instead of values, this helper trait exists to automatically
45/// perform this conversion.  It is implemented for functions up to an
46/// arity of 5 parameters.
47///
48/// For each argument the conversion is performed via the [`ArgType`]
49/// trait which is implemented for many common types.  For manual
50/// conversions the [`from_args`] utility should be used.
51pub trait FunctionArgs<'a> {
52    /// The output type of the function arguments.
53    type Output;
54
55    /// Converts to function arguments from a slice of values.
56    #[doc(hidden)]
57    fn from_values(state: Option<&'a State>, values: &'a [Value]) -> Result<Self::Output, Error>;
58}
59
60/// Utility function to convert a slice of values into arguments.
61///
62/// This performs the same conversion that [`Function`](crate::functions::Function)
63/// performs.  It exists so that you one can leverage the same functionality when
64/// implementing [`Object::call_method`](crate::value::Object::call_method).
65///
66/// ```
67/// # use minijinja::value::from_args;
68/// # use minijinja::value::Value;
69/// # fn foo() -> Result<(), minijinja::Error> {
70/// # let args = vec![Value::from("foo"), Value::from(42i64)]; let args = &args[..];
71/// // args is &[Value]
72/// let (string, num): (&str, i64) = from_args(args)?;
73/// # Ok(()) } fn main() { foo().unwrap(); }
74/// ```
75///
76/// Note that only value conversions are supported which means that `&State` is not
77/// a valid conversion type.
78///
79/// You can also use this function to split positional and keyword arguments ([`Kwargs`]):
80///
81/// ```
82/// # use minijinja::value::{Value, Rest, Kwargs, from_args};
83/// # use minijinja::Error;
84/// # fn foo() -> Result<(), minijinja::Error> {
85/// # let args = vec![Value::from("foo"), Value::from(42i64)]; let args = &args[..];
86/// // args is &[Value], kwargs is Kwargs
87/// let (args, kwargs): (&[Value], Kwargs) = from_args(args)?;
88/// # Ok(())
89/// # } fn main() { foo().unwrap(); }
90/// ```
91#[inline(always)]
92pub fn from_args<'a, Args>(values: &'a [Value]) -> Result<Args, Error>
93where
94    Args: FunctionArgs<'a, Output = Args>,
95{
96    Args::from_values(None, values)
97}
98
99/// A trait implemented by all filter/test argument types.
100///
101/// This trait is used by [`FunctionArgs`].  It's implemented for many common
102/// types that are typically passed to filters, tests or functions.  It's
103/// implemented for the following types:
104///
105/// * eval state: [`&State`](crate::State) (see below for notes)
106/// * unsigned integers: [`u8`], [`u16`], [`u32`], [`u64`], [`u128`], [`usize`]
107/// * signed integers: [`i8`], [`i16`], [`i32`], [`i64`], [`i128`]
108/// * floats: [`f32`], [`f64`]
109/// * bool: [`bool`]
110/// * string: [`String`], [`&str`], `Cow<'_, str>`, [`char`]
111/// * bytes: [`&[u8]`][`slice`]
112/// * values: [`Value`], `&Value`
113/// * vectors: [`Vec<T>`]
114/// * objects: [`DynObject`], [`Arc<T>`], `&T` (where `T` is an [`Object`])
115/// * serde deserializable: [`ViaDeserialize<T>`](crate::value::deserialize::ViaDeserialize)
116/// * keyword arguments: [`Kwargs`]
117/// * leftover arguments: [`Rest<T>`]
118///
119/// The type is also implemented for optional values (`Option<T>`) which is used
120/// to encode optional parameters to filters, functions or tests.  Additionally
121/// it's implemented for [`Rest<T>`] which is used to encode the remaining arguments
122/// of a function call.
123///
124/// ## Notes on Borrowing
125///
126/// Note on that there is an important difference between `String` and `&str`:
127/// the former will be valid for all values and an implicit conversion to string
128/// via [`ToString`] will take place, for the latter only values which are already
129/// strings will be passed.  A compromise between the two is `Cow<'_, str>` which
130/// will behave like `String` but borrows when possible.
131///
132/// Byte slices will borrow out of values carrying bytes or strings.  In the latter
133/// case the utf-8 bytes are returned.
134///
135/// There are also further restrictions imposed on borrowing in some situations.
136/// For instance you cannot implicitly borrow out of sequences which means that
137/// for instance `Vec<&str>` is not a legal argument.
138///
139/// ## Notes on State
140///
141/// When `&State` is used, it does not consume a passed parameter.  This means that
142/// a filter that takes `(&State, String)` actually only has one argument.  The
143/// state is passed implicitly.
144pub trait ArgType<'a> {
145    /// The output type of this argument.
146    type Output;
147
148    #[doc(hidden)]
149    fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error>;
150
151    #[doc(hidden)]
152    fn from_value_owned(_value: Value) -> Result<Self::Output, Error> {
153        Err(Error::new(
154            ErrorKind::InvalidOperation,
155            "type conversion is not legal in this situation (implicit borrow)",
156        ))
157    }
158
159    #[doc(hidden)]
160    fn from_state_and_value(
161        state: Option<&'a State>,
162        value: Option<&'a Value>,
163    ) -> Result<(Self::Output, usize), Error> {
164        if value.map_or(false, |x| x.is_undefined())
165            && state.map_or(false, |x| {
166                matches!(x.undefined_behavior(), UndefinedBehavior::Strict)
167            })
168        {
169            Err(Error::from(ErrorKind::UndefinedError))
170        } else {
171            Ok((ok!(Self::from_value(value)), 1))
172        }
173    }
174
175    #[doc(hidden)]
176    #[inline(always)]
177    fn from_state_and_values(
178        state: Option<&'a State>,
179        values: &'a [Value],
180        offset: usize,
181    ) -> Result<(Self::Output, usize), Error> {
182        Self::from_state_and_value(state, values.get(offset))
183    }
184
185    #[doc(hidden)]
186    #[inline(always)]
187    fn is_trailing() -> bool {
188        false
189    }
190}
191
192macro_rules! tuple_impls {
193    ( $( $name:ident )* * $rest_name:ident ) => {
194        impl<'a, $($name,)* $rest_name> FunctionArgs<'a> for ($($name,)* $rest_name,)
195            where $($name: ArgType<'a>,)* $rest_name: ArgType<'a>
196        {
197            type Output = ($($name::Output,)* $rest_name::Output ,);
198
199            fn from_values(state: Option<&'a State>, mut values: &'a [Value]) -> Result<Self::Output, Error> {
200                #![allow(non_snake_case, unused)]
201                $( let $name; )*
202                let mut $rest_name = None;
203                let mut idx = 0;
204
205                // special case: the last type is marked trailing (eg: for Kwargs) and we have at
206                // least one value.  In that case we need to read it first before going to the rest
207                // of the arguments.  This is needed to support from_args::<(&[Value], Kwargs)>
208                // or similar.
209                let rest_first = $rest_name::is_trailing() && !values.is_empty();
210                if rest_first {
211                    let (val, offset) = ok!($rest_name::from_state_and_values(state, values, values.len() - 1));
212                    $rest_name = Some(val);
213                    values = &values[..values.len() - offset];
214                }
215                $(
216                    let (val, offset) = ok!($name::from_state_and_values(state, values, idx));
217                    $name = val;
218                    idx += offset;
219                )*
220
221                if !rest_first {
222                    let (val, offset) = ok!($rest_name::from_state_and_values(state, values, idx));
223                    $rest_name = Some(val);
224                    idx += offset;
225                }
226
227                if values.get(idx).is_some() {
228                    Err(Error::from(ErrorKind::TooManyArguments))
229                } else {
230                    // SAFETY: this is safe because both no matter what `rest_first` is set to
231                    // the rest_name variable is set at this point.
232                    Ok(($($name,)* unsafe { $rest_name.unwrap_unchecked() },))
233                }
234            }
235        }
236    };
237}
238
239impl<'a> FunctionArgs<'a> for () {
240    type Output = ();
241
242    fn from_values(_state: Option<&'a State>, values: &'a [Value]) -> Result<Self::Output, Error> {
243        if values.is_empty() {
244            Ok(())
245        } else {
246            Err(Error::from(ErrorKind::TooManyArguments))
247        }
248    }
249}
250
251tuple_impls! { *A }
252tuple_impls! { A *B }
253tuple_impls! { A B *C }
254tuple_impls! { A B C *D }
255tuple_impls! { A B C D *E }
256
257impl From<ValueRepr> for Value {
258    #[inline(always)]
259    fn from(val: ValueRepr) -> Value {
260        Value(val)
261    }
262}
263
264impl<'a> From<&'a [u8]> for Value {
265    #[inline(always)]
266    fn from(val: &'a [u8]) -> Self {
267        ValueRepr::Bytes(Arc::new(val.into())).into()
268    }
269}
270
271impl<'a> From<&'a str> for Value {
272    #[inline(always)]
273    fn from(val: &'a str) -> Self {
274        SmallStr::try_new(val)
275            .map(|small_str| Value(ValueRepr::SmallStr(small_str)))
276            .unwrap_or_else(|| Value::from(val.to_string()))
277    }
278}
279
280impl<'a> From<&'a String> for Value {
281    #[inline(always)]
282    fn from(val: &'a String) -> Self {
283        Value::from(val.as_str())
284    }
285}
286
287impl From<String> for Value {
288    #[inline(always)]
289    fn from(val: String) -> Self {
290        ValueRepr::String(Arc::from(val), StringType::Normal).into()
291    }
292}
293
294impl<'a> From<Cow<'a, str>> for Value {
295    #[inline(always)]
296    fn from(val: Cow<'a, str>) -> Self {
297        match val {
298            Cow::Borrowed(x) => x.into(),
299            Cow::Owned(x) => x.into(),
300        }
301    }
302}
303
304impl From<Arc<str>> for Value {
305    fn from(value: Arc<str>) -> Self {
306        Value(ValueRepr::String(value, StringType::Normal))
307    }
308}
309
310impl From<()> for Value {
311    #[inline(always)]
312    fn from(_: ()) -> Self {
313        ValueRepr::None.into()
314    }
315}
316
317impl<V: Into<Value>> FromIterator<V> for Value {
318    fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
319        Value::from_object(iter.into_iter().map(Into::into).collect::<Vec<Value>>())
320    }
321}
322
323impl<K: Into<Value>, V: Into<Value>> FromIterator<(K, V)> for Value {
324    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
325        Value::from_object(
326            iter.into_iter()
327                .map(|(k, v)| (k.into(), v.into()))
328                .collect::<ValueMap>(),
329        )
330    }
331}
332
333macro_rules! value_from {
334    ($src:ty, $dst:ident) => {
335        impl From<$src> for Value {
336            #[inline(always)]
337            fn from(val: $src) -> Self {
338                ValueRepr::$dst(val as _).into()
339            }
340        }
341    };
342}
343
344impl From<i128> for Value {
345    #[inline(always)]
346    fn from(val: i128) -> Self {
347        ValueRepr::I128(Packed(val)).into()
348    }
349}
350
351impl From<u128> for Value {
352    #[inline(always)]
353    fn from(val: u128) -> Self {
354        ValueRepr::U128(Packed(val)).into()
355    }
356}
357
358impl From<char> for Value {
359    #[inline(always)]
360    fn from(val: char) -> Self {
361        let mut buf = [0u8; 4];
362        ValueRepr::SmallStr(SmallStr::try_new(val.encode_utf8(&mut buf)).unwrap()).into()
363    }
364}
365
366value_from!(bool, Bool);
367value_from!(u8, U64);
368value_from!(u16, U64);
369value_from!(u32, U64);
370value_from!(u64, U64);
371value_from!(i8, I64);
372value_from!(i16, I64);
373value_from!(i32, I64);
374value_from!(i64, I64);
375value_from!(f32, F64);
376value_from!(f64, F64);
377value_from!(Arc<Vec<u8>>, Bytes);
378value_from!(DynObject, Object);
379
380fn unsupported_conversion(kind: ValueKind, target: &str) -> Error {
381    Error::new(
382        ErrorKind::InvalidOperation,
383        format!("cannot convert {kind} to {target}"),
384    )
385}
386
387macro_rules! primitive_try_from {
388    ($ty:ident, {
389        $($pat:pat $(if $if_expr:expr)? => $expr:expr,)*
390    }) => {
391        impl TryFrom<Value> for $ty {
392            type Error = Error;
393
394            fn try_from(value: Value) -> Result<Self, Self::Error> {
395                match value.0 {
396                    $($pat $(if $if_expr)? => TryFrom::try_from($expr).ok(),)*
397                    _ => None
398                }.ok_or_else(|| unsupported_conversion(value.kind(), stringify!($ty)))
399            }
400        }
401
402        impl<'a> ArgType<'a> for $ty {
403            type Output = Self;
404            fn from_value(value: Option<&Value>) -> Result<Self, Error> {
405                match value {
406                    Some(value) => TryFrom::try_from(value.clone()),
407                    None => Err(Error::from(ErrorKind::MissingArgument))
408                }
409            }
410
411            fn from_value_owned(value: Value) -> Result<Self, Error> {
412                TryFrom::try_from(value)
413            }
414        }
415    }
416}
417
418macro_rules! primitive_int_try_from {
419    ($ty:ident) => {
420        primitive_try_from!($ty, {
421            ValueRepr::Bool(val) => val as usize,
422            ValueRepr::I64(val) => val,
423            ValueRepr::U64(val) => val,
424            // for the intention here see Key::from_borrowed_value
425            ValueRepr::F64(val) if (val as i64 as f64 == val) => val as i64,
426            ValueRepr::I128(val) => val.0,
427            ValueRepr::U128(val) => val.0,
428        });
429    }
430}
431
432primitive_int_try_from!(u8);
433primitive_int_try_from!(u16);
434primitive_int_try_from!(u32);
435primitive_int_try_from!(u64);
436primitive_int_try_from!(u128);
437primitive_int_try_from!(i8);
438primitive_int_try_from!(i16);
439primitive_int_try_from!(i32);
440primitive_int_try_from!(i64);
441primitive_int_try_from!(i128);
442primitive_int_try_from!(usize);
443
444primitive_try_from!(bool, {
445    ValueRepr::Bool(val) => val,
446});
447primitive_try_from!(char, {
448    ValueRepr::String(ref val, _) => {
449        let mut char_iter = val.chars();
450        ok!(char_iter.next().filter(|_| char_iter.next().is_none()).ok_or_else(|| {
451            unsupported_conversion(ValueKind::String, "non single character string")
452        }))
453    },
454    ValueRepr::SmallStr(ref val) => {
455        let mut char_iter = val.as_str().chars();
456        ok!(char_iter.next().filter(|_| char_iter.next().is_none()).ok_or_else(|| {
457            unsupported_conversion(ValueKind::String, "non single character string")
458        }))
459    },
460});
461primitive_try_from!(f32, {
462    ValueRepr::U64(val) => val as f32,
463    ValueRepr::I64(val) => val as f32,
464    ValueRepr::U128(val) => val.0 as f32,
465    ValueRepr::I128(val) => val.0 as f32,
466    ValueRepr::F64(val) => val as f32,
467});
468primitive_try_from!(f64, {
469    ValueRepr::U64(val) => val as f64,
470    ValueRepr::I64(val) => val as f64,
471    ValueRepr::U128(val) => val.0 as f64,
472    ValueRepr::I128(val) => val.0 as f64,
473    ValueRepr::F64(val) => val,
474});
475
476impl<'a> ArgType<'a> for &str {
477    type Output = &'a str;
478
479    fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
480        match value {
481            Some(value) => value
482                .as_str()
483                .ok_or_else(|| Error::new(ErrorKind::InvalidOperation, "value is not a string")),
484            None => Err(Error::from(ErrorKind::MissingArgument)),
485        }
486    }
487}
488
489impl TryFrom<Value> for Arc<str> {
490    type Error = Error;
491
492    fn try_from(value: Value) -> Result<Self, Self::Error> {
493        match value.0 {
494            ValueRepr::String(x, _) => Ok(x),
495            ValueRepr::SmallStr(x) => Ok(Arc::from(x.as_str())),
496            ValueRepr::Bytes(ref x) => Ok(Arc::from(String::from_utf8_lossy(x))),
497            _ => Err(Error::new(
498                ErrorKind::InvalidOperation,
499                "value is not a string",
500            )),
501        }
502    }
503}
504
505impl<'a> ArgType<'a> for Arc<str> {
506    type Output = Arc<str>;
507
508    fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
509        match value {
510            Some(value) => TryFrom::try_from(value.clone()),
511            None => Err(Error::from(ErrorKind::MissingArgument)),
512        }
513    }
514}
515
516impl<'a> ArgType<'a> for &[u8] {
517    type Output = &'a [u8];
518
519    fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
520        match value {
521            Some(value) => value
522                .as_bytes()
523                .ok_or_else(|| Error::new(ErrorKind::InvalidOperation, "value is not in bytes")),
524            None => Err(Error::from(ErrorKind::MissingArgument)),
525        }
526    }
527}
528
529impl<'a, T: ArgType<'a>> ArgType<'a> for Option<T> {
530    type Output = Option<T::Output>;
531
532    fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
533        match value {
534            Some(value) => {
535                if value.is_undefined() || value.is_none() {
536                    Ok(None)
537                } else {
538                    T::from_value(Some(value)).map(Some)
539                }
540            }
541            None => Ok(None),
542        }
543    }
544
545    fn from_value_owned(value: Value) -> Result<Self::Output, Error> {
546        if value.is_undefined() || value.is_none() {
547            Ok(None)
548        } else {
549            T::from_value_owned(value).map(Some)
550        }
551    }
552}
553
554impl<'a> ArgType<'a> for Cow<'_, str> {
555    type Output = Cow<'a, str>;
556
557    #[inline(always)]
558    fn from_value(value: Option<&'a Value>) -> Result<Cow<'a, str>, Error> {
559        match value {
560            Some(value) => Ok(match value.0 {
561                ValueRepr::String(ref s, _) => Cow::Borrowed(s as &str),
562                ValueRepr::SmallStr(ref s) => Cow::Borrowed(s.as_str()),
563                _ => {
564                    if value.is_kwargs() {
565                        return Err(Error::new(
566                            ErrorKind::InvalidOperation,
567                            "cannot convert kwargs to string",
568                        ));
569                    }
570                    Cow::Owned(value.to_string())
571                }
572            }),
573            None => Err(Error::from(ErrorKind::MissingArgument)),
574        }
575    }
576}
577
578impl<'a> ArgType<'a> for &Value {
579    type Output = &'a Value;
580
581    #[inline(always)]
582    fn from_value(value: Option<&'a Value>) -> Result<&'a Value, Error> {
583        match value {
584            Some(value) => Ok(value),
585            None => Err(Error::from(ErrorKind::MissingArgument)),
586        }
587    }
588}
589
590impl<'a> ArgType<'a> for &[Value] {
591    type Output = &'a [Value];
592
593    #[inline(always)]
594    fn from_value(value: Option<&'a Value>) -> Result<&'a [Value], Error> {
595        match value {
596            Some(value) => Ok(std::slice::from_ref(value)),
597            None => Err(Error::from(ErrorKind::MissingArgument)),
598        }
599    }
600
601    fn from_state_and_values(
602        _state: Option<&'a State>,
603        values: &'a [Value],
604        offset: usize,
605    ) -> Result<(&'a [Value], usize), Error> {
606        let args = values.get(offset..).unwrap_or_default();
607        Ok((args, args.len()))
608    }
609}
610
611impl<'a, T: Object + 'static> ArgType<'a> for &T {
612    type Output = &'a T;
613
614    #[inline(always)]
615    fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
616        match value {
617            Some(value) => value
618                .downcast_object_ref()
619                .ok_or_else(|| Error::new(ErrorKind::InvalidOperation, "expected object")),
620            None => Err(Error::from(ErrorKind::MissingArgument)),
621        }
622    }
623}
624
625impl<'a, T: Object + 'static> ArgType<'a> for Arc<T> {
626    type Output = Arc<T>;
627
628    #[inline(always)]
629    fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
630        match value {
631            Some(value) => value
632                .downcast_object()
633                .ok_or_else(|| Error::new(ErrorKind::InvalidOperation, "expected object")),
634            None => Err(Error::from(ErrorKind::MissingArgument)),
635        }
636    }
637}
638
639/// Utility type to capture remaining arguments.
640///
641/// In some cases you might want to have a variadic function.  In that case
642/// you can define the last argument to a [`Filter`](crate::filters::Filter),
643/// [`Test`](crate::tests::Test) or [`Function`](crate::functions::Function)
644/// this way.  The `Rest<T>` type will collect all the remaining arguments
645/// here.  It's implemented for all [`ArgType`]s.  The type itself deref's
646/// into the inner vector.
647///
648/// ```
649/// # use minijinja::Environment;
650/// # let mut env = Environment::new();
651/// use minijinja::State;
652/// use minijinja::value::Rest;
653///
654/// fn sum(_state: &State, values: Rest<i64>) -> i64 {
655///     values.iter().sum()
656/// }
657/// ```
658#[derive(Debug)]
659pub struct Rest<T>(pub Vec<T>);
660
661impl<T> Deref for Rest<T> {
662    type Target = Vec<T>;
663
664    fn deref(&self) -> &Self::Target {
665        &self.0
666    }
667}
668
669impl<T> DerefMut for Rest<T> {
670    fn deref_mut(&mut self) -> &mut Self::Target {
671        &mut self.0
672    }
673}
674
675impl<'a, T: ArgType<'a, Output = T>> ArgType<'a> for Rest<T> {
676    type Output = Self;
677
678    fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
679        Ok(Rest(ok!(value
680            .iter()
681            .map(|v| T::from_value(Some(v)))
682            .collect::<Result<_, _>>())))
683    }
684
685    fn from_state_and_values(
686        _state: Option<&'a State>,
687        values: &'a [Value],
688        offset: usize,
689    ) -> Result<(Self, usize), Error> {
690        let args = values.get(offset..).unwrap_or_default();
691        Ok((
692            Rest(ok!(args
693                .iter()
694                .map(|v| T::from_value(Some(v)))
695                .collect::<Result<_, _>>())),
696            args.len(),
697        ))
698    }
699}
700
701/// Utility to accept keyword arguments.
702///
703/// Keyword arguments are represented as regular values as the last argument
704/// in an argument list.  This can be quite complex to use manually so this
705/// type is added as a utility.  You can use [`get`](Self::get) to fetch a
706/// single keyword argument and then use [`assert_all_used`](Self::assert_all_used)
707/// to make sure extra arguments create an error.
708///
709/// Here an example of a function modifying values in different ways.
710///
711/// ```
712/// use minijinja::value::{Value, Kwargs};
713/// use minijinja::Error;
714///
715/// fn modify(mut values: Vec<Value>, options: Kwargs) -> Result<Vec<Value>, Error> {
716///     // get pulls a parameter of any type.  Same as from_args.  For optional
717///     // boolean values the type inference is particularly convenient.
718///     if let Some(true) = options.get("reverse")? {
719///         values.reverse();
720///     }
721///     if let Some(limit) = options.get("limit")? {
722///         values.truncate(limit);
723///     }
724///     options.assert_all_used()?;
725///     Ok(values)
726/// }
727/// ```
728///
729/// If for whatever reason you need a value again you can use [`Into`] to
730/// convert it back into a [`Value`].  This is particularly useful when performing
731/// calls into values.  To create a [`Kwargs`] object from scratch you can use
732/// [`FromIterator`]:
733///
734/// ```
735/// use minijinja::value::{Value, Kwargs};
736/// let kwargs = Kwargs::from_iter([
737///     ("foo", Value::from(true)),
738///     ("bar", Value::from(42)),
739/// ]);
740/// let value = Value::from(kwargs);
741/// assert!(value.is_kwargs());
742/// ```
743///
744/// When working with [`Rest`] you can use [`from_args`] to split all arguments into
745/// positional arguments and keyword arguments:
746///
747/// ```
748/// # use minijinja::value::{Value, Rest, Kwargs, from_args};
749/// # use minijinja::Error;
750/// fn my_func(args: Rest<Value>) -> Result<Value, Error> {
751///     let (args, kwargs) = from_args::<(&[Value], Kwargs)>(&args)?;
752///     // do something with args and kwargs
753/// # todo!()
754/// }
755/// ```
756#[derive(Debug, Clone)]
757pub struct Kwargs {
758    pub(crate) values: Arc<KwargsValues>,
759    used: RefCell<HashSet<String>>,
760}
761
762#[repr(transparent)]
763#[derive(Default, Debug)]
764pub(crate) struct KwargsValues(ValueMap);
765
766impl Deref for KwargsValues {
767    type Target = ValueMap;
768
769    fn deref(&self) -> &Self::Target {
770        &self.0
771    }
772}
773
774impl KwargsValues {
775    fn as_value_map<'a>(self: &'a Arc<Self>) -> &'a Arc<ValueMap> {
776        // SAFETY: this is safe because of repr(transparent)
777        unsafe { std::mem::transmute(self) }
778    }
779}
780
781impl Object for KwargsValues {
782    fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
783        self.as_value_map().get_value(key)
784    }
785
786    fn enumerate(self: &Arc<Self>) -> Enumerator {
787        self.as_value_map().enumerate()
788    }
789}
790
791impl<'a> ArgType<'a> for Kwargs {
792    type Output = Self;
793
794    fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
795        match value {
796            Some(value) => {
797                Kwargs::extract(value).ok_or_else(|| Error::from(ErrorKind::MissingArgument))
798            }
799            None => Ok(Kwargs::new(Default::default())),
800        }
801    }
802
803    fn from_state_and_values(
804        _state: Option<&'a State>,
805        values: &'a [Value],
806        offset: usize,
807    ) -> Result<(Self, usize), Error> {
808        let args = values
809            .get(offset)
810            .and_then(Kwargs::extract)
811            .map(|kwargs| (kwargs, 1))
812            .unwrap_or_else(|| (Kwargs::new(Default::default()), 0));
813
814        Ok(args)
815    }
816
817    fn is_trailing() -> bool {
818        true
819    }
820}
821
822impl Kwargs {
823    fn new(map: Arc<KwargsValues>) -> Kwargs {
824        Kwargs {
825            values: map,
826            used: RefCell::new(HashSet::new()),
827        }
828    }
829
830    /// Given a value, extracts the kwargs if there are any.
831    pub(crate) fn extract(value: &Value) -> Option<Kwargs> {
832        value
833            .as_object()
834            .and_then(|x| x.downcast::<KwargsValues>())
835            .map(Kwargs::new)
836    }
837
838    /// Wraps a value map into kwargs.
839    pub(crate) fn wrap(map: ValueMap) -> Value {
840        Value::from_object(KwargsValues(map))
841    }
842
843    /// Get a single argument from the kwargs but don't mark it as used.
844    pub fn peek<'a, T>(&'a self, key: &'a str) -> Result<T, Error>
845    where
846        T: ArgType<'a, Output = T>,
847    {
848        T::from_value(self.values.get(&Value::from(key))).map_err(|mut err| {
849            if err.kind() == ErrorKind::MissingArgument && err.detail().is_none() {
850                err.set_detail(format!("missing keyword argument '{}'", key));
851            }
852            err
853        })
854    }
855
856    /// Gets a single argument from the kwargs and marks it as used.
857    ///
858    /// This method works pretty much like [`from_args`] and marks any parameter
859    /// used internally.  For optional arguments you would typically use
860    /// `Option<T>` and for non optional ones directly `T`.
861    ///
862    /// Examples:
863    ///
864    /// ```
865    /// # use minijinja::Error;
866    /// # use minijinja::value::Kwargs; fn f(kwargs: Kwargs) -> Result<(), Error> {
867    /// // f(int=42) -> Some(42)
868    /// // f() -> None
869    /// let optional_int: Option<u32> = kwargs.get("int")?;
870    /// // f(int=42) -> 42
871    /// // f() -> Error
872    /// let required_int: u32 = kwargs.get("int")?;
873    /// # Ok(()) }
874    /// ```
875    ///
876    /// If you don't want to mark it as used, us [`peek`](Self::peek) instead.
877    pub fn get<'a, T>(&'a self, key: &'a str) -> Result<T, Error>
878    where
879        T: ArgType<'a, Output = T>,
880    {
881        let rv = ok!(self.peek::<T>(key));
882        self.used.borrow_mut().insert(key.to_string());
883        Ok(rv)
884    }
885
886    /// Checks if a keyword argument exists.
887    pub fn has(&self, key: &str) -> bool {
888        self.values.contains_key(&Value::from(key))
889    }
890
891    /// Iterates over all passed keyword arguments.
892    pub fn args(&self) -> impl Iterator<Item = &str> {
893        self.values.iter().filter_map(|x| x.0.as_str())
894    }
895
896    /// Asserts that all kwargs were used.
897    pub fn assert_all_used(&self) -> Result<(), Error> {
898        let used = self.used.borrow();
899        for key in self.values.keys() {
900            if let Some(key) = key.as_str() {
901                if !used.contains(key) {
902                    return Err(Error::new(
903                        ErrorKind::TooManyArguments,
904                        format!("unknown keyword argument '{}'", key),
905                    ));
906                }
907            } else {
908                return Err(Error::new(
909                    ErrorKind::InvalidOperation,
910                    "non string keys passed to kwargs",
911                ));
912            }
913        }
914        Ok(())
915    }
916}
917
918impl FromIterator<(String, Value)> for Kwargs {
919    fn from_iter<T>(iter: T) -> Self
920    where
921        T: IntoIterator<Item = (String, Value)>,
922    {
923        Kwargs::new(Arc::new(KwargsValues(
924            iter.into_iter().map(|(k, v)| (Value::from(k), v)).collect(),
925        )))
926    }
927}
928
929impl<'a> FromIterator<(&'a str, Value)> for Kwargs {
930    fn from_iter<T>(iter: T) -> Self
931    where
932        T: IntoIterator<Item = (&'a str, Value)>,
933    {
934        Kwargs::new(Arc::new(KwargsValues(
935            iter.into_iter().map(|(k, v)| (Value::from(k), v)).collect(),
936        )))
937    }
938}
939
940impl From<Kwargs> for Value {
941    fn from(value: Kwargs) -> Self {
942        Value::from_dyn_object(value.values)
943    }
944}
945
946impl TryFrom<Value> for Kwargs {
947    type Error = Error;
948
949    fn try_from(value: Value) -> Result<Self, Self::Error> {
950        match value.0 {
951            ValueRepr::Undefined => Ok(Kwargs::new(Default::default())),
952            ValueRepr::Object(_) => {
953                Kwargs::extract(&value).ok_or_else(|| Error::from(ErrorKind::InvalidOperation))
954            }
955            _ => Err(Error::from(ErrorKind::InvalidOperation)),
956        }
957    }
958}
959
960impl<'a> ArgType<'a> for Value {
961    type Output = Self;
962
963    fn from_state_and_value(
964        _state: Option<&'a State>,
965        value: Option<&'a Value>,
966    ) -> Result<(Self::Output, usize), Error> {
967        Ok((ok!(Self::from_value(value)), 1))
968    }
969
970    fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
971        match value {
972            Some(value) => Ok(value.clone()),
973            None => Err(Error::from(ErrorKind::MissingArgument)),
974        }
975    }
976
977    fn from_value_owned(value: Value) -> Result<Self, Error> {
978        Ok(value)
979    }
980}
981
982impl<'a> ArgType<'a> for String {
983    type Output = Self;
984
985    fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
986        match value {
987            Some(value) => {
988                if value.is_kwargs() {
989                    return Err(Error::new(
990                        ErrorKind::InvalidOperation,
991                        "cannot convert kwargs to string",
992                    ));
993                }
994                Ok(value.to_string())
995            }
996            None => Err(Error::from(ErrorKind::MissingArgument)),
997        }
998    }
999
1000    fn from_value_owned(value: Value) -> Result<Self, Error> {
1001        Ok(value.to_string())
1002    }
1003}
1004
1005impl<'a, T: ArgType<'a, Output = T>> ArgType<'a> for Vec<T> {
1006    type Output = Vec<T>;
1007
1008    fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
1009        match value {
1010            None => Ok(Vec::new()),
1011            Some(value) => {
1012                let iter = ok!(value
1013                    .as_object()
1014                    .filter(|x| matches!(x.repr(), ObjectRepr::Seq | ObjectRepr::Iterable))
1015                    .and_then(|x| x.try_iter())
1016                    .ok_or_else(|| { Error::new(ErrorKind::InvalidOperation, "not iterable") }));
1017                let mut rv = Vec::new();
1018                for value in iter {
1019                    rv.push(ok!(T::from_value_owned(value)));
1020                }
1021                Ok(rv)
1022            }
1023        }
1024    }
1025
1026    fn from_value_owned(value: Value) -> Result<Self, Error> {
1027        let iter = ok!(value
1028            .as_object()
1029            .filter(|x| matches!(x.repr(), ObjectRepr::Seq | ObjectRepr::Iterable))
1030            .and_then(|x| x.try_iter())
1031            .ok_or_else(|| { Error::new(ErrorKind::InvalidOperation, "not iterable") }));
1032        let mut rv = Vec::new();
1033        for value in iter {
1034            rv.push(ok!(T::from_value_owned(value)));
1035        }
1036        Ok(rv)
1037    }
1038}
1039
1040impl<'a> ArgType<'a> for DynObject {
1041    type Output = Self;
1042
1043    fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
1044        value
1045            .ok_or_else(|| Error::from(ErrorKind::MissingArgument))
1046            .and_then(|v| Self::from_value_owned(v.clone()))
1047    }
1048
1049    fn from_value_owned(value: Value) -> Result<Self, Error> {
1050        value
1051            .as_object()
1052            .cloned()
1053            .ok_or_else(|| Error::new(ErrorKind::InvalidOperation, "not an object"))
1054    }
1055}
1056
1057impl From<Value> for String {
1058    fn from(val: Value) -> Self {
1059        val.to_string()
1060    }
1061}
1062
1063impl From<usize> for Value {
1064    fn from(val: usize) -> Self {
1065        Value::from(val as u64)
1066    }
1067}
1068
1069impl From<isize> for Value {
1070    fn from(val: isize) -> Self {
1071        Value::from(val as i64)
1072    }
1073}
1074
1075impl<I: Into<Value>> From<Option<I>> for Value {
1076    fn from(value: Option<I>) -> Self {
1077        match value {
1078            Some(value) => value.into(),
1079            None => Value::from(()),
1080        }
1081    }
1082}
1083
1084#[cfg(test)]
1085mod tests {
1086    use super::*;
1087
1088    #[test]
1089    fn test_as_f64() {
1090        let v = Value::from(42u32);
1091        let f: f64 = v.try_into().unwrap();
1092        assert_eq!(f, 42.0);
1093        let v = Value::from(42.5);
1094        let f: f64 = v.try_into().unwrap();
1095        assert_eq!(f, 42.5);
1096    }
1097
1098    #[test]
1099    fn test_split_kwargs() {
1100        let args = [
1101            Value::from(42),
1102            Value::from(true),
1103            Value::from(Kwargs::from_iter([
1104                ("foo", Value::from(1)),
1105                ("bar", Value::from(2)),
1106            ])),
1107        ];
1108        let (args, kwargs) = from_args::<(&[Value], Kwargs)>(&args).unwrap();
1109        assert_eq!(args, &[Value::from(42), Value::from(true)]);
1110        assert_eq!(kwargs.get::<Value>("foo").unwrap(), Value::from(1));
1111        assert_eq!(kwargs.get::<Value>("bar").unwrap(), Value::from(2));
1112    }
1113
1114    #[test]
1115    fn test_kwargs_fails_string_conversion() {
1116        let kwargs = Kwargs::from_iter([("foo", Value::from(1)), ("bar", Value::from(2))]);
1117        let args = [Value::from(kwargs)];
1118
1119        let result = from_args::<(String,)>(&args);
1120        assert!(result.is_err());
1121        assert_eq!(
1122            result.unwrap_err().to_string(),
1123            "invalid operation: cannot convert kwargs to string"
1124        );
1125
1126        let result = from_args::<(Cow<str>,)>(&args);
1127        assert!(result.is_err());
1128        assert_eq!(
1129            result.unwrap_err().to_string(),
1130            "invalid operation: cannot convert kwargs to string"
1131        );
1132    }
1133
1134    #[test]
1135    fn test_optional_none() {
1136        let (one,) = from_args::<(Option<i32>,)>(args!(None::<i32>)).unwrap();
1137        assert!(one.is_none());
1138        let (one,) = from_args::<(Option<i32>,)>(args!(Some(Value::UNDEFINED))).unwrap();
1139        assert!(one.is_none());
1140    }
1141}