1use core::marker::PhantomData;
2
3use ::rust_alloc::sync::Arc;
4
5use crate as rune;
6use crate::alloc;
7use crate::alloc::borrow::Cow;
8use crate::alloc::prelude::*;
9use crate::compile::context::{AttributeMacroHandler, MacroHandler};
10use crate::compile::{self, meta};
11use crate::function::{Function, FunctionKind, InstanceFunction};
12use crate::item::IntoComponent;
13use crate::macros::{MacroContext, TokenStream};
14use crate::module::AssociatedKey;
15use crate::runtime::{FunctionHandler, MaybeTypeOf, Protocol, TypeInfo, TypeOf};
16use crate::{Hash, ItemBuf};
17
18mod sealed {
19 use crate::params::Params;
20 use crate::runtime::Protocol;
21
22 pub trait Sealed {}
23
24 impl Sealed for &str {}
25 impl Sealed for &Protocol {}
26 impl<T, const N: usize> Sealed for Params<T, N> {}
27}
28
29pub type FunctionMeta = fn() -> alloc::Result<FunctionMetaData>;
39
40pub type MacroMeta = fn() -> alloc::Result<MacroMetaData>;
50
51pub struct FunctionData {
53 pub(crate) item: ItemBuf,
54 pub(crate) handler: Arc<FunctionHandler>,
55 #[cfg(feature = "doc")]
56 pub(crate) is_async: bool,
57 #[cfg(feature = "doc")]
58 pub(crate) args: Option<usize>,
59 #[cfg(feature = "doc")]
60 pub(crate) argument_types: Box<[meta::DocType]>,
61 #[cfg(feature = "doc")]
62 pub(crate) return_type: meta::DocType,
63}
64
65impl FunctionData {
66 pub(crate) fn from_raw(item: ItemBuf, handler: Arc<FunctionHandler>) -> Self {
67 Self {
68 item,
69 handler,
70 #[cfg(feature = "doc")]
71 is_async: false,
72 #[cfg(feature = "doc")]
73 args: None,
74 #[cfg(feature = "doc")]
75 argument_types: Box::default(),
76 #[cfg(feature = "doc")]
77 return_type: meta::DocType::empty(),
78 }
79 }
80
81 #[inline]
82 pub(crate) fn new<F, A, N, K>(name: N, f: F) -> alloc::Result<Self>
83 where
84 F: Function<A, K, Return: MaybeTypeOf>,
85 N: IntoComponent,
86 A: FunctionArgs,
87 K: FunctionKind,
88 {
89 Ok(Self {
90 item: ItemBuf::with_item([name])?,
91 handler: Arc::new(move |stack, addr, args, output| {
92 f.fn_call(stack, addr, args, output)
93 }),
94 #[cfg(feature = "doc")]
95 is_async: K::IS_ASYNC,
96 #[cfg(feature = "doc")]
97 args: Some(F::ARGS),
98 #[cfg(feature = "doc")]
99 argument_types: A::into_box()?,
100 #[cfg(feature = "doc")]
101 return_type: F::Return::maybe_type_of()?,
102 })
103 }
104}
105
106pub struct FunctionMacroData {
108 pub(crate) item: ItemBuf,
109 pub(crate) handler: Arc<MacroHandler>,
110}
111
112impl FunctionMacroData {
113 #[inline]
114 pub(crate) fn new<F, N>(name: N, f: F) -> alloc::Result<Self>
115 where
116 F: 'static
117 + Send
118 + Sync
119 + Fn(&mut MacroContext<'_, '_, '_>, &TokenStream) -> compile::Result<TokenStream>,
120 N: IntoIterator,
121 N::Item: IntoComponent,
122 {
123 Ok(Self {
124 item: ItemBuf::with_item(name)?,
125 handler: Arc::new(f),
126 })
127 }
128}
129
130pub struct AttributeMacroData {
132 pub(crate) item: ItemBuf,
133 pub(crate) handler: Arc<AttributeMacroHandler>,
134}
135
136impl AttributeMacroData {
137 #[inline]
138 pub(crate) fn new<F, N>(name: N, f: F) -> alloc::Result<Self>
139 where
140 F: 'static
141 + Send
142 + Sync
143 + Fn(
144 &mut MacroContext<'_, '_, '_>,
145 &TokenStream,
146 &TokenStream,
147 ) -> compile::Result<TokenStream>,
148 N: IntoIterator,
149 N::Item: IntoComponent,
150 {
151 Ok(Self {
152 item: ItemBuf::with_item(name)?,
153 handler: Arc::new(f),
154 })
155 }
156}
157
158#[derive(Debug, TryClone)]
160#[non_exhaustive]
161#[doc(hidden)]
162pub struct AssociatedName {
163 pub kind: meta::AssociatedKind,
165 pub function_parameters: Hash,
167 #[cfg(feature = "doc")]
168 pub parameter_types: Vec<Hash>,
169}
170
171impl AssociatedName {
172 pub(crate) fn index(protocol: &'static Protocol, index: usize) -> Self {
173 Self {
174 kind: meta::AssociatedKind::IndexFn(protocol, index),
175 function_parameters: Hash::EMPTY,
176 #[cfg(feature = "doc")]
177 parameter_types: Vec::new(),
178 }
179 }
180}
181
182pub trait ToInstance: self::sealed::Sealed {
184 #[doc(hidden)]
186 fn to_instance(self) -> alloc::Result<AssociatedName>;
187}
188
189pub trait ToFieldFunction: self::sealed::Sealed {
191 #[doc(hidden)]
192 fn to_field_function(self, protocol: &'static Protocol) -> alloc::Result<AssociatedName>;
193}
194
195impl ToInstance for &'static str {
196 #[inline]
197 fn to_instance(self) -> alloc::Result<AssociatedName> {
198 Ok(AssociatedName {
199 kind: meta::AssociatedKind::Instance(Cow::Borrowed(self)),
200 function_parameters: Hash::EMPTY,
201 #[cfg(feature = "doc")]
202 parameter_types: Vec::new(),
203 })
204 }
205}
206
207impl ToFieldFunction for &'static str {
208 #[inline]
209 fn to_field_function(self, protocol: &'static Protocol) -> alloc::Result<AssociatedName> {
210 Ok(AssociatedName {
211 kind: meta::AssociatedKind::FieldFn(protocol, Cow::Borrowed(self)),
212 function_parameters: Hash::EMPTY,
213 #[cfg(feature = "doc")]
214 parameter_types: Vec::new(),
215 })
216 }
217}
218
219pub struct Associated {
221 pub(crate) name: AssociatedName,
223 pub(crate) container: Hash,
225 pub(crate) container_type_info: TypeInfo,
227}
228
229impl Associated {
230 pub fn new(name: AssociatedName, container: Hash, container_type_info: TypeInfo) -> Self {
232 Self {
233 name,
234 container,
235 container_type_info,
236 }
237 }
238
239 pub fn from_type<T>(name: AssociatedName) -> alloc::Result<Self>
241 where
242 T: TypeOf,
243 {
244 Ok(Self {
245 name,
246 container: T::HASH,
247 container_type_info: T::type_info(),
248 })
249 }
250
251 pub(crate) fn as_key(&self) -> alloc::Result<AssociatedKey> {
253 Ok(AssociatedKey {
254 type_hash: self.container,
255 kind: self.name.kind.try_clone()?,
256 parameters: self.name.function_parameters,
257 })
258 }
259}
260
261pub struct AssociatedFunctionData {
263 pub(crate) associated: Associated,
264 pub(crate) handler: Arc<FunctionHandler>,
265 #[cfg(feature = "doc")]
266 pub(crate) is_async: bool,
267 #[cfg(feature = "doc")]
268 pub(crate) args: Option<usize>,
269 #[cfg(feature = "doc")]
270 pub(crate) argument_types: Box<[meta::DocType]>,
271 #[cfg(feature = "doc")]
272 pub(crate) return_type: meta::DocType,
273}
274
275impl AssociatedFunctionData {
276 pub(crate) fn from_raw(associated: Associated, handler: Arc<FunctionHandler>) -> Self {
277 Self {
278 associated,
279 handler,
280 #[cfg(feature = "doc")]
281 is_async: false,
282 #[cfg(feature = "doc")]
283 args: None,
284 #[cfg(feature = "doc")]
285 argument_types: Box::default(),
286 #[cfg(feature = "doc")]
287 return_type: meta::DocType::empty(),
288 }
289 }
290
291 #[inline]
292 pub(crate) fn from_function<F, A, K>(associated: Associated, f: F) -> alloc::Result<Self>
293 where
294 F: Function<A, K, Return: MaybeTypeOf>,
295 A: FunctionArgs,
296 K: FunctionKind,
297 {
298 Ok(Self {
299 associated,
300 handler: Arc::new(move |stack, addr, args, output| {
301 f.fn_call(stack, addr, args, output)
302 }),
303 #[cfg(feature = "doc")]
304 is_async: K::IS_ASYNC,
305 #[cfg(feature = "doc")]
306 args: Some(F::ARGS),
307 #[cfg(feature = "doc")]
308 argument_types: A::into_box()?,
309 #[cfg(feature = "doc")]
310 return_type: F::Return::maybe_type_of()?,
311 })
312 }
313
314 #[inline]
315 pub(crate) fn from_instance_function<F, A, K>(name: AssociatedName, f: F) -> alloc::Result<Self>
316 where
317 F: InstanceFunction<A, K, Return: MaybeTypeOf>,
318 A: FunctionArgs,
319 K: FunctionKind,
320 {
321 Ok(Self {
322 associated: Associated::from_type::<F::Instance>(name)?,
323 handler: Arc::new(move |stack, addr, args, output| {
324 f.fn_call(stack, addr, args, output)
325 }),
326 #[cfg(feature = "doc")]
327 is_async: K::IS_ASYNC,
328 #[cfg(feature = "doc")]
329 args: Some(F::ARGS),
330 #[cfg(feature = "doc")]
331 argument_types: A::into_box()?,
332 #[cfg(feature = "doc")]
333 return_type: F::Return::maybe_type_of()?,
334 })
335 }
336}
337
338#[doc(hidden)]
343pub enum FunctionMetaKind {
344 #[doc(hidden)]
345 Function(FunctionData),
346 #[doc(hidden)]
347 AssociatedFunction(AssociatedFunctionData),
348}
349
350impl FunctionMetaKind {
351 #[doc(hidden)]
352 #[inline]
353 pub fn function<N, F, A, K>(name: N, f: F) -> alloc::Result<FunctionBuilder<N, F, A, K>>
354 where
355 F: Function<A, K, Return: MaybeTypeOf>,
356 A: FunctionArgs,
357 K: FunctionKind,
358 {
359 Ok(FunctionBuilder::new(name, f))
360 }
361
362 #[doc(hidden)]
363 #[inline]
364 pub fn instance<N, F, A, K>(name: N, f: F) -> alloc::Result<Self>
365 where
366 N: ToInstance,
367 F: InstanceFunction<A, K, Return: MaybeTypeOf>,
368 A: FunctionArgs,
369 K: FunctionKind,
370 {
371 Ok(Self::AssociatedFunction(
372 AssociatedFunctionData::from_instance_function(name.to_instance()?, f)?,
373 ))
374 }
375}
376
377#[doc(hidden)]
378pub struct FunctionBuilder<N, F, A, K> {
379 name: N,
380 f: F,
381 _marker: PhantomData<(A, K)>,
382}
383
384impl<N, F, A, K> FunctionBuilder<N, F, A, K> {
385 pub(crate) fn new(name: N, f: F) -> Self {
386 Self {
387 name,
388 f,
389 _marker: PhantomData,
390 }
391 }
392}
393
394impl<N, F, A, K> FunctionBuilder<N, F, A, K>
395where
396 F: Function<A, K, Return: MaybeTypeOf>,
397 A: FunctionArgs,
398 K: FunctionKind,
399{
400 #[doc(hidden)]
401 #[inline]
402 pub fn build(self) -> alloc::Result<FunctionMetaKind>
403 where
404 N: IntoComponent,
405 {
406 Ok(FunctionMetaKind::Function(FunctionData::new(
407 self.name, self.f,
408 )?))
409 }
410
411 #[doc(hidden)]
412 #[inline]
413 pub fn build_associated<T>(self) -> alloc::Result<FunctionMetaKind>
414 where
415 N: ToInstance,
416 T: TypeOf,
417 {
418 let associated = Associated::from_type::<T>(self.name.to_instance()?)?;
419
420 Ok(FunctionMetaKind::AssociatedFunction(
421 AssociatedFunctionData::from_function(associated, self.f)?,
422 ))
423 }
424
425 #[doc(hidden)]
426 #[inline]
427 pub fn build_associated_with(
428 self,
429 container: Hash,
430 container_type_info: TypeInfo,
431 ) -> alloc::Result<FunctionMetaKind>
432 where
433 N: ToInstance,
434 {
435 let name = self.name.to_instance()?;
436 let associated = Associated::new(name, container, container_type_info);
437
438 Ok(FunctionMetaKind::AssociatedFunction(
439 AssociatedFunctionData::from_function(associated, self.f)?,
440 ))
441 }
442}
443
444#[doc(hidden)]
449pub enum MacroMetaKind {
450 #[doc(hidden)]
451 Function(FunctionMacroData),
452 #[doc(hidden)]
453 Attribute(AttributeMacroData),
454}
455
456impl MacroMetaKind {
457 #[doc(hidden)]
458 #[inline]
459 pub fn function<F, N>(name: N, f: F) -> alloc::Result<Self>
460 where
461 F: 'static
462 + Send
463 + Sync
464 + Fn(&mut MacroContext<'_, '_, '_>, &TokenStream) -> compile::Result<TokenStream>,
465 N: IntoIterator,
466 N::Item: IntoComponent,
467 {
468 Ok(Self::Function(FunctionMacroData::new(name, f)?))
469 }
470
471 #[doc(hidden)]
472 #[inline]
473 pub fn attribute<F, N>(name: N, f: F) -> alloc::Result<Self>
474 where
475 F: 'static
476 + Send
477 + Sync
478 + Fn(
479 &mut MacroContext<'_, '_, '_>,
480 &TokenStream,
481 &TokenStream,
482 ) -> compile::Result<TokenStream>,
483 N: IntoIterator,
484 N::Item: IntoComponent,
485 {
486 Ok(Self::Attribute(AttributeMacroData::new(name, f)?))
487 }
488}
489
490#[doc(hidden)]
495pub struct MacroMetaData {
496 #[doc(hidden)]
497 pub kind: MacroMetaKind,
498 #[doc(hidden)]
499 pub name: &'static str,
500 #[doc(hidden)]
501 pub docs: &'static [&'static str],
502}
503
504#[doc(hidden)]
506pub struct FunctionMetaStatics {
507 #[doc(hidden)]
508 pub name: &'static str,
509 #[doc(hidden)]
510 pub deprecated: Option<&'static str>,
511 #[doc(hidden)]
512 pub docs: &'static [&'static str],
513 #[doc(hidden)]
514 pub arguments: &'static [&'static str],
515}
516
517#[doc(hidden)]
522pub struct FunctionMetaData {
523 #[doc(hidden)]
524 pub kind: FunctionMetaKind,
525 #[doc(hidden)]
526 pub statics: FunctionMetaStatics,
527}
528
529#[doc(hidden)]
531pub trait FunctionArgs {
532 #[doc(hidden)]
533 fn into_box() -> alloc::Result<Box<[meta::DocType]>>;
534
535 #[doc(hidden)]
536 fn len() -> usize;
537}
538
539macro_rules! iter_function_args {
540 ($count:expr $(, $ty:ident $var:ident $num:expr)*) => {
541 impl<$($ty,)*> FunctionArgs for ($($ty,)*)
542 where
543 $($ty: MaybeTypeOf,)*
544 {
545 #[inline]
546 fn into_box() -> alloc::Result<Box<[meta::DocType]>> {
547 try_vec![$(<$ty as MaybeTypeOf>::maybe_type_of()?),*].try_into_boxed_slice()
548 }
549
550 #[inline]
551 fn len() -> usize {
552 $count
553 }
554 }
555 }
556}
557
558repeat_macro!(iter_function_args);