rune/
function_meta.rs

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
29/// Type used to collect and store function metadata through the
30/// `#[rune::function]` macro.
31///
32/// This is the argument type for
33/// [`Module::function_meta`][crate::module::Module::function_meta], and is from
34/// a public API perspective completely opaque and might change for any release.
35///
36/// Calling and making use of `FunctionMeta` manually despite this warning might
37/// lead to future breakage.
38pub type FunctionMeta = fn() -> alloc::Result<FunctionMetaData>;
39
40/// Type used to collect and store function metadata through the
41/// `#[rune::macro_]` macro.
42///
43/// This is the argument type for
44/// [`Module::macro_meta`][crate::module::Module::macro_meta], and is from a
45/// public API perspective completely opaque and might change for any release.
46///
47/// Calling and making use of `MacroMeta` manually despite this warning might
48/// lead to future breakage.
49pub type MacroMeta = fn() -> alloc::Result<MacroMetaData>;
50
51/// Runtime data for a function.
52pub 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
106/// Runtime data for a macro.
107pub 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
130/// Runtime data for an attribute macro.
131pub 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/// A descriptor for an instance function.
159#[derive(Debug, TryClone)]
160#[non_exhaustive]
161#[doc(hidden)]
162pub struct AssociatedName {
163    /// The name of the instance function.
164    pub kind: meta::AssociatedKind,
165    /// Parameters hash.
166    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
182/// Trait used solely to construct an instance function.
183pub trait ToInstance: self::sealed::Sealed {
184    /// Get information on the naming of the instance function.
185    #[doc(hidden)]
186    fn to_instance(self) -> alloc::Result<AssociatedName>;
187}
188
189/// Trait used to determine what can be used as an instance function name.
190pub 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
219/// The full naming of an associated item.
220pub struct Associated {
221    /// The name of the associated item.
222    pub(crate) name: AssociatedName,
223    /// The container the associated item is associated with.
224    pub(crate) container: Hash,
225    /// Type info for the container the associated item is associated with.
226    pub(crate) container_type_info: TypeInfo,
227}
228
229impl Associated {
230    /// Construct a raw associated name.
231    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    /// Construct an associated name from static type information.
240    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    /// Get unique key for the associated item.
252    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
261/// Runtime data for an associated function.
262pub 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/// The kind of a [`FunctionMeta`].
339///
340/// Even though this is marked as `pub`, this is private API. If you use this it
341/// might cause breakage.
342#[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/// The kind of a [`FunctionMeta`].
445///
446/// Even though this is marked as `pub`, this is private API. If you use this it
447/// might cause breakage.
448#[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/// The data of a [`MacroMeta`].
491///
492/// Even though this is marked as `pub`, this is private API. If you use this it
493/// might cause breakage.
494#[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/// Function metadata statics.
505#[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/// The data of a [`FunctionMeta`].
518///
519/// Even though this is marked as `pub`, this is private API. If you use this it
520/// might cause breakage.
521#[doc(hidden)]
522pub struct FunctionMetaData {
523    #[doc(hidden)]
524    pub kind: FunctionMetaKind,
525    #[doc(hidden)]
526    pub statics: FunctionMetaStatics,
527}
528
529/// Trait implement allowing the collection of function argument types.
530#[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);