1 | use std::ops::RangeBounds; |
2 | |
3 | use proc_macro2::{Ident, Span}; |
4 | use syn::LitStr; |
5 | |
6 | /// Joins the arguments with `&&` operators. |
7 | macro_rules! and { |
8 | ($($expr:expr),* $(,)?) => { |
9 | $($expr)&&* |
10 | }; |
11 | } |
12 | |
13 | /// Joins the arguments with `||` operators. |
14 | #[cfg (feature = "terminfo" )] |
15 | macro_rules! or { |
16 | ($($expr:expr),* $(,)?) => { |
17 | $($expr)||* |
18 | }; |
19 | } |
20 | |
21 | /// Creates a new [`Ident`] which can be tokenized. |
22 | pub fn ident(s: &str) -> Ident { |
23 | Ident::new(string:s, Span::call_site()) |
24 | } |
25 | |
26 | /// Creates a new [`struct@LitStr`] which can be tokenized. |
27 | pub fn literal_string(s: &str) -> LitStr { |
28 | LitStr::new(value:s, Span::call_site()) |
29 | } |
30 | |
31 | /// Unfortunately, unless a nightly compiler is used, this function will actually only return the |
32 | /// original input span. |
33 | /// |
34 | /// Returns the subspan corresponding to the range of `inside` inside `input`, considering that: |
35 | /// - `input` is exactly `&input_lit_str.value()`, |
36 | /// - `inside` is a subslice of `input`, |
37 | /// |
38 | /// Warning: may panic if the conditions are not met. |
39 | /// TODO: improve safety |
40 | pub fn inner_span<'a>(input: &'a str, input_lit_str: &LitStr, inside: &'a str) -> Span { |
41 | let input_offset: usize = (inside.as_ptr() as usize) - (input.as_ptr() as usize); |
42 | let range: Range = input_offset + 1..input_offset + inside.len() + 1; |
43 | subspan(input_lit_str.span(), range).unwrap_or_else(|| input_lit_str.span()) |
44 | } |
45 | |
46 | /// Returns a subspan of the given span. |
47 | /// |
48 | /// TODO: the implementation is really... wtf! But i didn't find a better way to do it. |
49 | fn subspan<R: RangeBounds<usize>>(span: Span, range: R) -> Option<Span> { |
50 | let mut lit: Literal = proc_macro2::Literal::i8_suffixed(0); // wtf... |
51 | lit.set_span(span); |
52 | lit.subspan(range) |
53 | } |
54 | |