struct_baker/interpolation/
mod.rs1use std::{
2 error::Error,
3 fmt,
4 fmt::{Display, Formatter},
5 ops::Deref,
6};
7
8use proc_macro2::{TokenStream, TokenTree};
9use quote::{quote, ToTokens};
10use syn::{parse2, parse_quote};
11
12use crate::{functions::BakeableFnOnce, Bake, Bakeable};
13
14pub mod helper;
15pub mod ops;
16mod flatten;
17
18pub use flatten::*;
19
20#[derive(Debug, Clone)]
21pub enum Interpolatable<T> {
22 Inter(TokenTree),
23 Actual(T),
24}
25
26impl<T> Interpolatable<T> {
27 pub fn new_inter(stream: TokenStream) -> Self {
29 Self::Inter(parse_quote!({{#stream}.into()}))
30 }
31
32 pub fn new_inter_raw(tree: TokenTree) -> Self {
36 Self::Inter(parse_quote!(#tree.into()))
37 }
38}
39
40impl<T: Bake + PartialEq> PartialEq for Interpolatable<T> {
44 fn eq(&self, other: &Self) -> bool {
45 match (self, other) {
46 (Self::Actual(a), Self::Actual(b)) => a.eq(b),
47 _ => false,
48 }
49 }
50}
51
52#[derive(Debug)]
53pub struct RuntimeInterpolationError(TokenTree);
54
55impl Display for RuntimeInterpolationError {
56 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
57 write!(f, "Runtime Interpolation. {}", self.0)
58 }
59}
60
61impl Error for RuntimeInterpolationError {}
62
63trait UnwrapInterpolation<T> {
64 fn unwrap(self) -> T;
65}
66
67impl<T: Bake> Bakeable for Interpolatable<T> {
68 fn bake(&self) -> TokenStream {
69 match self {
70 Interpolatable::Inter(tree) => tree.to_token_stream(),
71 Interpolatable::Actual(t) => t.to_stream(),
72 }
73 }
74}
75
76pub trait Interpolate<T> {
77 fn fit(self) -> Result<T, RuntimeInterpolationError>;
78
79 fn force_fit(self) -> T
81 where
82 Self: Sized,
83 {
84 self.fit().expect("Interpolated during runtime")
85 }
86
87 #[cfg(feature = "nom")]
88 fn nom<I>(self, input: I) -> Result<T, nom::Err<nom::error::Error<I>>>
90 where
91 Self: Sized,
92 {
93 self.fit().map_err(|_| {
94 nom::Err::Failure(nom::error::Error::new(input, nom::error::ErrorKind::Fail))
95 })
96 }
97}
98
99impl<T: Bake> Interpolate<T> for Interpolatable<T> {
100 fn fit(self) -> Result<T, RuntimeInterpolationError> {
101 match self {
102 Interpolatable::Actual(t) => Ok(t),
103 Interpolatable::Inter(tree) => Err(RuntimeInterpolationError(tree)),
104 }
105 }
106}
107
108impl<'a, T: Bake> Interpolate<&'a T> for &'a Interpolatable<T> {
109 fn fit(self) -> Result<&'a T, RuntimeInterpolationError> {
110 match self {
111 Interpolatable::Actual(t) => Ok(t),
112 Interpolatable::Inter(tree) => Err(RuntimeInterpolationError(tree.clone())),
113 }
114 }
115}
116
117impl<T: Bake> Interpolate<Interpolatable<T>> for Interpolatable<T> {
118 fn fit(self) -> Result<Interpolatable<T>, RuntimeInterpolationError> {
119 Ok(self)
120 }
121}
122
123impl<T: Bake> Interpolate<Interpolatable<T>> for T {
124 fn fit(self) -> Result<Interpolatable<T>, RuntimeInterpolationError> {
125 Ok(Interpolatable::Actual(self))
126 }
127}
128
129impl<T: Bake> Interpolate<T> for T {
130 fn fit(self) -> Result<T, RuntimeInterpolationError> {
131 Ok(self)
132 }
133}
134
135impl<T: Bake> From<T> for Interpolatable<T> {
136 fn from(value: T) -> Self {
137 Self::Actual(value)
138 }
139}
140
141impl<T> From<TokenTree> for Interpolatable<T> {
142 fn from(value: TokenTree) -> Self {
143 Self::Inter(value)
144 }
145}
146
147impl From<RuntimeInterpolationError> for syn::Error {
148 fn from(value: RuntimeInterpolationError) -> Self {
149 Self::new_spanned(value.0, "Runtime interpolation is not possible")
150 }
151}
152
153pub trait IntoInterpolation
154where
155 Self: Sized + Bake,
156{
157 fn interpolate(self) -> Interpolatable<Self>;
158}
159
160impl<T: Bake> IntoInterpolation for T {
161 fn interpolate(self) -> Interpolatable<Self> {
162 Interpolatable::Actual(self)
163 }
164}
165
166impl<T: Bake> Deref for Interpolatable<T> {
168 type Target = T;
169 fn deref(&self) -> &Self::Target {
170 self.fit().expect("Can not deref an interpolation")
171 }
172}
173
174impl<B: Bake> From<Vec<Interpolatable<B>>> for Interpolatable<Vec<B>> {
175 fn from(value: Vec<Interpolatable<B>>) -> Self {
176 let mut visited: Vec<B> = Vec::with_capacity(value.len());
177 let mut result: Option<Vec<TokenTree>> = None;
178
179 use Interpolatable::*;
180
181 for element in value {
182 match element {
183 Inter(tree) => {
184 if result.is_none() {
185 let mut v = Vec::with_capacity(visited.len());
186 v.extend(visited.iter().map(|b| b.to_token_tree()));
187 result = Some(v);
188 }
189 result.as_mut().unwrap().push(tree);
190 }
191 Actual(item) => match result.as_mut() {
192 Some(vec) => vec.push(item.to_token_tree()),
193 None => visited.push(item),
194 },
195 }
196 }
197
198 match result {
199 Some(list) => Inter(parse_quote!({ vec![#(#list.into(),)*] })),
200 None => Actual(visited),
201 }
202 }
203}
204
205impl<B: Bake, Collection: FromIterator<B>> FromIterator<Interpolatable<B>>
206 for Interpolatable<Collection>
207{
208 fn from_iter<T: IntoIterator<Item = Interpolatable<B>>>(iter: T) -> Self {
209 let iter = iter.into_iter();
210 let mut visited: Vec<B> = Vec::with_capacity(iter.size_hint().1.unwrap_or_default());
211 let mut result: Option<Vec<TokenTree>> = None;
212
213 use Interpolatable::*;
214
215 for element in iter {
216 match element {
217 Inter(tree) => {
218 if result.is_none() {
219 let mut v = Vec::with_capacity(visited.len());
220 v.extend(visited.iter().map(|b| b.to_token_tree()));
221 result = Some(v);
222 }
223 result.as_mut().unwrap().push(parse_quote!({#tree.into()}));
224 }
225 Actual(item) => match result.as_mut() {
226 Some(vec) => vec.push(item.to_token_tree()),
227 None => visited.push(item),
228 },
229 }
230 }
231
232 match result {
233 Some(list) => Inter(parse_quote!({FromIterator::from_iter([#(#list,)*])})),
234 None => Actual(FromIterator::from_iter(visited)),
235 }
236 }
237}
238
239impl<T: Bake> Interpolatable<T> {
240 pub fn map<F, U: Bake>(self, f: BakeableFnOnce<F, T, U>) -> Interpolatable<U>
245 where
246 F: FnOnce(T) -> U,
247 {
248 use Interpolatable::*;
249 match self {
250 Actual(inner) => Actual(f.call(inner)),
251 Inter(tree) => {
252 let function_path = f.bake();
253 Inter(parse2(quote!(#function_path(#tree.into()))).unwrap())
254 }
255 }
256 }
257
258 pub fn actual(self) -> Option<T> {
259 match self {
260 Interpolatable::Inter(_) => None,
261 Interpolatable::Actual(t) => Some(t),
262 }
263 }
264
265 pub fn tree(self) -> Option<TokenTree> {
266 match self {
267 Interpolatable::Inter(tree) => Some(tree),
268 Interpolatable::Actual(_) => None,
269 }
270 }
271}