velcro_core/
seq.rs

1use crate::value::{Value, ValueExpr, ValueIterExpr, Verbatim};
2use proc_macro2::TokenStream;
3use quote::ToTokens;
4use std::marker::PhantomData;
5use syn::parse::{self, Parse, ParseStream};
6use syn::punctuated::{Pair, Punctuated};
7use syn::Token;
8
9/// A comma-delimited sequence of `Value`s, used for macros with list-like input.
10pub struct SeqInput<V = Verbatim> {
11    values: Punctuated<Value<V>, Token![,]>,
12    _phantom: PhantomData<V>,
13}
14
15impl<V> Parse for SeqInput<V>
16where
17    Value<V>: Parse,
18{
19    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
20        Ok(SeqInput {
21            values: input.parse_terminated(Value::parse)?,
22            _phantom: PhantomData,
23        })
24    }
25}
26
27impl<V> SeqInput<V>
28where
29    ValueExpr<V>: ToTokens,
30    ValueIterExpr<V>: ToTokens,
31{
32    /// Returns true if the sequence contains no spread values
33    pub fn is_simple(&self) -> bool {
34        self.values.iter().all(Value::is_simple)
35    }
36
37    pub fn values(&self) -> impl ExactSizeIterator<Item = &Value<V>> {
38        self.values.iter()
39    }
40
41    pub fn simple_output(self) -> TokenStream {
42        self.values
43            .into_pairs()
44            .map(Pair::into_tuple)
45            .map(|(value, delim)| Pair::new(value.into_token_stream(), delim).into_token_stream())
46            .collect()
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use std::str::FromStr as _;
54    use syn::Expr;
55
56    #[test]
57    fn parse_empty_input_as_empty_sequence() {
58        let tokens = TokenStream::from_str("").unwrap();
59        let seq: SeqInput<Verbatim> = syn::parse2(tokens).unwrap();
60        assert!(seq.values().next().is_none());
61    }
62
63    #[test]
64    fn parse_single_expression_as_one_value_of_one() {
65        let tokens = TokenStream::from_str("a + b").unwrap();
66        let seq: SeqInput<Verbatim> = syn::parse2(tokens.clone()).unwrap();
67        let expected_expr: Expr = syn::parse2(tokens).unwrap();
68        let values: Vec<_> = seq.values().collect();
69        assert_eq!(values.len(), 1);
70        assert!(matches!(values[0], Value::One(ValueExpr { expr, .. }) if *expr == expected_expr));
71    }
72
73    #[test]
74    fn parse_single_spread_expression_as_one_value_of_many() {
75        let source = "..a + b";
76        let tokens = TokenStream::from_str(source).unwrap();
77        let seq: SeqInput<Verbatim> = syn::parse2(tokens).unwrap();
78        let expected_expr: Expr = {
79            let tokens = TokenStream::from_str(source.strip_prefix("..").unwrap()).unwrap();
80            syn::parse2(tokens).unwrap()
81        };
82        let values: Vec<_> = seq.values().collect();
83        assert_eq!(values.len(), 1);
84        assert!(
85            matches!(values[0], Value::Many(ValueIterExpr { expr, .. }) if *expr == expected_expr)
86        );
87    }
88
89    #[test]
90    fn empty_input_is_simple() {
91        let tokens = TokenStream::from_str("").unwrap();
92        let seq: SeqInput<Verbatim> = syn::parse2(tokens).unwrap();
93        assert!(seq.is_simple());
94    }
95
96    #[test]
97    fn non_spread_input_is_simple() {
98        let tokens = TokenStream::from_str("a, b, c").unwrap();
99        let seq: SeqInput<Verbatim> = syn::parse2(tokens).unwrap();
100        assert!(seq.is_simple());
101    }
102
103    #[test]
104    fn spread_input_is_not_simple() {
105        let tokens = TokenStream::from_str("a, ..b, c").unwrap();
106        let seq: SeqInput<Verbatim> = syn::parse2(tokens).unwrap();
107        assert!(!seq.is_simple());
108    }
109}