darling_core/util/
path_list.rs1use std::ops::Deref;
2
3use syn::{Meta, Path};
4
5use crate::ast::NestedMeta;
6use crate::{Error, FromMeta, Result};
7
8use super::path_to_string;
9
10#[derive(Debug, Default, Clone, PartialEq, Eq)]
22pub struct PathList(Vec<Path>);
23
24impl PathList {
25 pub fn new<T: Into<Path>>(vals: Vec<T>) -> Self {
27 PathList(vals.into_iter().map(T::into).collect())
28 }
29
30 pub fn to_strings(&self) -> Vec<String> {
32 self.0.iter().map(path_to_string).collect()
33 }
34
35 pub fn intersection<'a>(&'a self, other: &'a PathList) -> impl Iterator<Item = &'a Path> {
46 self.0.iter().filter(|path| other.0.contains(path))
47 }
48}
49
50impl Deref for PathList {
51 type Target = Vec<Path>;
52
53 fn deref(&self) -> &Self::Target {
54 &self.0
55 }
56}
57
58impl From<Vec<Path>> for PathList {
59 fn from(v: Vec<Path>) -> Self {
60 PathList(v)
61 }
62}
63
64impl FromMeta for PathList {
65 fn from_list(v: &[NestedMeta]) -> Result<Self> {
66 let mut paths = Vec::with_capacity(v.len());
67 for nmi in v {
68 if let NestedMeta::Meta(Meta::Path(ref path)) = *nmi {
69 paths.push(path.clone());
70 } else {
71 return Err(Error::unexpected_type("non-word").with_span(nmi));
72 }
73 }
74
75 Ok(PathList(paths))
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::PathList;
82 use crate::FromMeta;
83 use proc_macro2::TokenStream;
84 use quote::quote;
85 use syn::{parse_quote, Attribute, Meta};
86
87 fn pm(tokens: TokenStream) -> ::std::result::Result<Meta, String> {
89 let attribute: Attribute = parse_quote!(#[#tokens]);
90 Ok(attribute.meta)
91 }
92
93 fn fm<T: FromMeta>(tokens: TokenStream) -> T {
94 FromMeta::from_meta(&pm(tokens).expect("Tests should pass well-formed input"))
95 .expect("Tests should pass valid input")
96 }
97
98 #[test]
99 fn succeeds() {
100 let paths = fm::<PathList>(quote!(ignore(Debug, Clone, Eq)));
101 assert_eq!(
102 paths.to_strings(),
103 vec![
104 String::from("Debug"),
105 String::from("Clone"),
106 String::from("Eq")
107 ]
108 );
109 }
110
111 #[test]
114 fn fails_non_word() {
115 let input = PathList::from_meta(&pm(quote!(ignore(Debug, Clone = false))).unwrap());
116 let err = input.unwrap_err();
117 assert!(err.has_span());
118 }
119
120 #[test]
121 fn intersection() {
122 let left = fm::<PathList>(quote!(ignore(Debug, Clone, Eq)));
123 let right = fm::<PathList>(quote!(ignore(Clone, Eq, Clone)));
124 assert_eq!(
125 left.intersection(&right).cloned().collect::<Vec<_>>(),
126 vec![parse_quote!(Clone), parse_quote!(Eq)],
127 );
128 }
129}