1//! Utility functions.
2
3use proc_macro2::Span;
4use syn::{
5 punctuated::Punctuated, spanned::Spanned, Ident, Meta, MetaList, Path, PathArguments,
6 PathSegment, Result, Token,
7};
8
9use crate::error::Error;
10
11/// Convenience type to return two possible values.
12pub enum Either<L, R> {
13 /// `L` return value.
14 Left(L),
15 /// `R` return value.
16 Right(R),
17}
18
19/// Create [`PathSegment`] from [`str`].
20pub fn path_segment(ident: &str) -> PathSegment {
21 PathSegment {
22 ident: Ident::new(string:ident, Span::call_site()),
23 arguments: PathArguments::None,
24 }
25}
26
27/// Create [`Path`] from `[&str]`s.
28pub fn path_from_strs(segments: &[&str]) -> Path {
29 Path {
30 leading_colon: Some(<Token![::]>::default()),
31 segments: Punctuated::from_iter(segments.iter().map(|segment: &&str| path_segment(ident:segment))),
32 }
33}
34
35/// Create [`Path`] from `[&Ident]`s.
36pub fn path_from_idents(segments: &[&Ident]) -> Path {
37 Path {
38 leading_colon: None,
39 segments: Punctuated::from_iter(segments.iter().map(|ident: &&Ident| PathSegment {
40 ident: (*ident).clone(),
41 arguments: PathArguments::None,
42 })),
43 }
44}
45
46/// Create [`Path`] from a root [`Path`] and `[&str]`s.
47pub fn path_from_root_and_strs(root: Path, segments: &[&str]) -> Path {
48 Path {
49 leading_colon: root.leading_colon,
50 segments: rootimpl Iterator
51 .segments
52 .into_iter()
53 .chain(segments.iter().map(|segment: &&str| path_segment(ident:segment)))
54 .collect(),
55 }
56}
57
58/// Extension for [`MetaList`].
59pub trait MetaListExt {
60 /// Shorthand for parsing a [`MetaList`] into a list of [`Meta`]s.
61 fn parse_non_empty_nested_metas(&self) -> Result<Punctuated<Meta, Token![,]>>;
62}
63
64impl MetaListExt for MetaList {
65 fn parse_non_empty_nested_metas(&self) -> Result<Punctuated<Meta, Token![,]>> {
66 let list: Punctuated = self.parse_args_with(parser:Punctuated::<Meta, Token![,]>::parse_terminated)?;
67
68 if list.is_empty() {
69 return Err(Error::option_empty(self.span()));
70 }
71
72 Ok(list)
73 }
74}
75