Skip to main content

rune/runtime/
function.rs

1use core::fmt;
2use core::future::Future;
3
4use crate as rune;
5use crate::alloc::fmt::TryWrite;
6use crate::alloc::prelude::*;
7use crate::alloc::{self, Box, Vec};
8use crate::function;
9use crate::runtime;
10use crate::runtime::vm::Isolated;
11use crate::shared::AssertSend;
12use crate::sync::Arc;
13use crate::{Any, Hash};
14
15use super::{
16    Address, AnySequence, Args, Call, ConstValueBuf, Dismantle, Formatter, FromValue,
17    FunctionHandler, Globals, GuardedArgs, Handover, Output, OwnedTuple, Rtti, RuntimeContext,
18    RuntimeError, Stack, Unit, Value, Vm, VmCall, VmError, VmErrorKind, VmHalt,
19};
20
21/// The type of a function in Rune.
22///
23/// Functions can be called using call expression syntax, such as `<expr>()`.
24///
25/// There are multiple different kind of things which can be coerced into a
26/// function in Rune:
27/// * Regular functions.
28/// * Closures (which might or might not capture their environment).
29/// * Built-in constructors for tuple types (tuple structs, tuple variants).
30///
31/// # Examples
32///
33/// ```rune
34/// // Captures the constructor for the `Some(<value>)` tuple variant.
35/// let build_some = Some;
36/// assert_eq!(build_some(42), Some(42));
37///
38/// fn build(value) {
39///     Some(value)
40/// }
41///
42/// // Captures the function previously defined.
43/// let build_some = build;
44/// assert_eq!(build_some(42), Some(42));
45/// ```
46#[derive(Any, TryClone)]
47#[repr(transparent)]
48#[rune(item = ::std::ops, dismantle)]
49pub struct Function(FunctionImpl<Value>);
50
51impl Function {
52    /// Construct a [Function] from a Rust closure.
53    ///
54    /// # Examples
55    ///
56    /// ```
57    /// use rune::{Hash, Vm};
58    /// use rune::runtime::Function;
59    /// use rune::sync::Arc;
60    ///
61    /// let mut sources = rune::sources! {
62    ///     entry => {
63    ///         pub fn main(function) {
64    ///             function(41)
65    ///         }
66    ///     }
67    /// };
68    ///
69    /// let unit = rune::prepare(&mut sources).build()?;
70    /// let unit = Arc::try_new(unit)?;
71    /// let mut vm = Vm::without_runtime(unit)?;
72    ///
73    /// let function = Function::new(|value: u32| value + 1)?;
74    ///
75    /// assert_eq!(function.type_hash(), Hash::EMPTY);
76    ///
77    /// let value = vm.call(["main"], (function,))?;
78    /// let value: u32 = rune::from_value(value)?;
79    /// assert_eq!(value, 42);
80    /// # Ok::<_, rune::support::Error>(())
81    /// ```
82    ///
83    /// Asynchronous functions:
84    ///
85    /// ```
86    /// use rune::{Hash, Vm};
87    /// use rune::runtime::Function;
88    /// use rune::sync::Arc;
89    ///
90    /// # futures_executor::block_on(async move {
91    /// let mut sources = rune::sources! {
92    ///     entry => {
93    ///         pub async fn main(function) {
94    ///             function(41).await
95    ///         }
96    ///     }
97    /// };
98    ///
99    /// let unit = rune::prepare(&mut sources).build()?;
100    /// let unit = Arc::try_new(unit)?;
101    /// let mut vm = Vm::without_runtime(unit)?;
102    ///
103    /// let function = Function::new(|value: u32| async move { value + 1 })?;
104    ///
105    /// assert_eq!(function.type_hash(), Hash::EMPTY);
106    ///
107    /// let value = vm.async_call(["main"], (function,)).await?;
108    /// let value: u32 = rune::from_value(value)?;
109    /// assert_eq!(value, 42);
110    /// # Ok::<_, rune::support::Error>(())
111    /// # })?;
112    /// # Ok::<_, rune::support::Error>(())
113    /// ```
114    pub fn new<F, A, K>(f: F) -> alloc::Result<Self>
115    where
116        F: function::Function<A, K>,
117        K: function::FunctionKind,
118    {
119        Ok(Self(FunctionImpl {
120            inner: Inner::FnHandler(FnHandler {
121                handler: FunctionHandler::new(move |stack, addr, args, output| {
122                    f.call(stack, addr, args, output)
123                })?,
124                hash: Hash::EMPTY,
125            }),
126        }))
127    }
128
129    /// Perform an asynchronous call over the function which also implements
130    /// [Send].
131    pub async fn async_send_call<A, T>(&self, args: A) -> Result<T, VmError>
132    where
133        A: Send + GuardedArgs,
134        T: Send + FromValue,
135    {
136        self.0.async_send_call(args).await
137    }
138
139    /// Perform a call over the function represented by this function pointer.
140    ///
141    /// # Examples
142    ///
143    /// ```
144    /// use rune::{Hash, Vm};
145    /// use rune::runtime::Function;
146    /// use rune::sync::Arc;
147    ///
148    /// let mut sources = rune::sources! {
149    ///     entry => {
150    ///         fn add(a, b) {
151    ///             a + b
152    ///         }
153    ///
154    ///         pub fn main() { add }
155    ///     }
156    /// };
157    ///
158    /// let unit = rune::prepare(&mut sources).build()?;
159    /// let unit = Arc::try_new(unit)?;
160    /// let mut vm = Vm::without_runtime(unit)?;
161    ///
162    /// let value = vm.call(["main"], ())?;
163    ///
164    /// let value: Function = rune::from_value(value)?;
165    /// assert_eq!(value.call::<u32>((1, 2))?, 3);
166    /// # Ok::<_, rune::support::Error>(())
167    /// ```
168    pub fn call<T>(&self, args: impl GuardedArgs) -> Result<T, VmError>
169    where
170        T: FromValue,
171    {
172        self.0.call(args)
173    }
174
175    /// Call with the given virtual machine. This allows for certain
176    /// optimizations, like avoiding the allocation of a new vm state in case
177    /// the call is internal.
178    ///
179    /// A stop reason will be returned in case the function call results in
180    /// a need to suspend the execution.
181    pub(crate) fn call_with_vm(
182        &self,
183        vm: &mut Vm,
184        addr: Address,
185        args: usize,
186        out: Output,
187    ) -> Result<Option<VmHalt>, VmError> {
188        self.0.call_with_vm(vm, addr, args, out)
189    }
190
191    /// Create a function pointer from a handler.
192    pub(crate) fn from_handler(handler: FunctionHandler, hash: Hash) -> Self {
193        Self(FunctionImpl::from_handler(handler, hash))
194    }
195
196    /// Create a function pointer from an offset.
197    pub(crate) fn from_vm_offset(
198        context: Arc<RuntimeContext>,
199        unit: Arc<Unit>,
200        globals: Globals,
201        offset: usize,
202        call: Call,
203        args: usize,
204        hash: Hash,
205    ) -> Self {
206        Self(FunctionImpl::from_offset(
207            context, unit, globals, offset, call, args, hash,
208        ))
209    }
210
211    /// Create a function pointer from an offset.
212    pub(crate) fn from_vm_closure(
213        context: Arc<RuntimeContext>,
214        unit: Arc<Unit>,
215        globals: Globals,
216        offset: usize,
217        call: Call,
218        args: usize,
219        environment: Box<[Value]>,
220        hash: Hash,
221    ) -> Self {
222        Self(FunctionImpl::from_closure(
223            context,
224            unit,
225            globals,
226            offset,
227            call,
228            args,
229            environment,
230            hash,
231        ))
232    }
233
234    /// Create a function pointer from an offset.
235    pub(crate) fn from_unit_struct(rtti: Arc<Rtti>) -> Self {
236        Self(FunctionImpl::from_unit_struct(rtti))
237    }
238
239    /// Create a function pointer from an offset.
240    pub(crate) fn from_tuple_struct(rtti: Arc<Rtti>, args: usize) -> Self {
241        Self(FunctionImpl::from_tuple_struct(rtti, args))
242    }
243
244    /// Type [Hash][struct@Hash] of the underlying function.
245    ///
246    /// # Examples
247    ///
248    /// The type hash of a top-level function matches what you get out of
249    /// [Hash::type_hash].
250    ///
251    /// ```
252    /// use rune::runtime::Function;
253    /// use rune::sync::Arc;
254    /// use rune::{Hash, Vm};
255    ///
256    /// let mut sources = rune::sources! {
257    ///     entry => {
258    ///         fn pony() { }
259    ///
260    ///         pub fn main() { pony }
261    ///     }
262    /// };
263    ///
264    /// let unit = rune::prepare(&mut sources).build()?;
265    /// let unit = Arc::try_new(unit)?;
266    /// let mut vm = Vm::without_runtime(unit)?;
267    ///
268    /// let pony = vm.call(["main"], ())?;
269    /// let pony: Function = rune::from_value(pony)?;
270    ///
271    /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"]));
272    /// # Ok::<_, rune::support::Error>(())
273    /// ```
274    pub fn type_hash(&self) -> Hash {
275        self.0.type_hash()
276    }
277
278    /// Try to convert into a [SyncFunction]. This might not be possible if this
279    /// function is something which is not [Sync], like a closure capturing
280    /// context which is not thread-safe.
281    ///
282    /// # Examples
283    ///
284    /// ```
285    /// use rune::{Hash, Vm};
286    /// use rune::runtime::Function;
287    /// use rune::sync::Arc;
288    ///
289    /// let mut sources = rune::sources! {
290    ///     entry => {
291    ///         fn pony() { }
292    ///
293    ///         pub fn main() { pony }
294    ///     }
295    /// };
296    ///
297    /// let unit = rune::prepare(&mut sources).build()?;
298    /// let unit = Arc::try_new(unit)?;
299    /// let mut vm = Vm::without_runtime(unit)?;
300    ///
301    /// let pony = vm.call(["main"], ())?;
302    /// let pony: Function = rune::from_value(pony)?;
303    ///
304    /// // This is fine, since `pony` is a free function.
305    /// let pony = pony.into_sync()?;
306    ///
307    /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"]));
308    /// # Ok::<_, rune::support::Error>(())
309    /// ```
310    ///
311    /// The following *does not* work, because we return a closure which tries
312    /// to make use of a [Generator][crate::runtime::Generator] which is not a
313    /// constant value.
314    ///
315    /// ```
316    /// use rune::runtime::Function;
317    /// use rune::sync::Arc;
318    /// use rune::{Hash, Vm};
319    ///
320    /// let mut sources = rune::sources! {
321    ///     entry => {
322    ///         fn generator() {
323    ///             yield 42;
324    ///         }
325    ///
326    ///         pub fn main() {
327    ///             let g = generator();
328    ///
329    ///             move || {
330    ///                 g.next()
331    ///             }
332    ///         }
333    ///     }
334    /// };
335    ///
336    /// let unit = rune::prepare(&mut sources).build()?;
337    /// let unit = Arc::try_new(unit)?;
338    /// let mut vm = Vm::without_runtime(unit)?;
339    ///
340    /// let closure = vm.call(["main"], ())?;
341    /// let closure: Function = rune::from_value(closure)?;
342    ///
343    /// // This is *not* fine since the returned closure has captured a
344    /// // generator which is not a constant value.
345    /// assert!(closure.into_sync().is_err());
346    /// # Ok::<_, rune::support::Error>(())
347    /// ```
348    pub fn into_sync(self) -> Result<SyncFunction, RuntimeError> {
349        Ok(SyncFunction(self.0.into_sync()?))
350    }
351
352    /// Clone a function.
353    ///
354    /// # Examples
355    ///
356    /// ```rune
357    /// fn function() {
358    ///     42
359    /// }
360    ///
361    /// let a = function;
362    /// let b = a.clone();
363    /// assert_eq!(a(), b());
364    /// ```
365    #[rune::function(keep, protocol = CLONE)]
366    fn clone(&self) -> Result<Function, VmError> {
367        Ok(self.try_clone()?)
368    }
369
370    /// Debug format a function.
371    ///
372    /// # Examples
373    ///
374    /// ```rune
375    /// fn function() {
376    ///     42
377    /// }
378    ///
379    /// println!("{function:?}");
380    /// ```
381    #[rune::function(keep, protocol = DEBUG_FMT)]
382    fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> {
383        write!(f, "{self:?}")
384    }
385}
386
387/// A callable sync function. This currently only supports a subset of values
388/// that are supported by the Vm.
389#[repr(transparent)]
390pub struct SyncFunction(FunctionImpl<ConstValueBuf>);
391
392assert_impl!(SyncFunction: Send + Sync);
393
394impl SyncFunction {
395    /// Perform an asynchronous call over the function which also implements
396    /// [Send].
397    ///
398    /// # Examples
399    ///
400    /// ```
401    /// use rune::runtime::SyncFunction;
402    /// use rune::sync::Arc;
403    /// use rune::{Hash, Vm};
404    ///
405    /// # futures_executor::block_on(async move {
406    /// let mut sources = rune::sources! {
407    ///     entry => {
408    ///         async fn add(a, b) {
409    ///             a + b
410    ///         }
411    ///
412    ///         pub fn main() { add }
413    ///     }
414    /// };
415    ///
416    /// let unit = rune::prepare(&mut sources).build()?;
417    /// let unit = Arc::try_new(unit)?;
418    /// let mut vm = Vm::without_runtime(unit)?;
419    ///
420    /// let add = vm.call(["main"], ())?;
421    /// let add: SyncFunction = rune::from_value(add)?;
422    ///
423    /// let value = add.async_send_call::<u32>((1, 2)).await?;
424    /// assert_eq!(value, 3);
425    /// # Ok::<_, rune::support::Error>(())
426    /// # })?;
427    /// # Ok::<_, rune::support::Error>(())
428    /// ```
429    pub async fn async_send_call<T>(&self, args: impl GuardedArgs + Send) -> Result<T, VmError>
430    where
431        T: Send + FromValue,
432    {
433        self.0.async_send_call(args).await
434    }
435
436    /// Perform a call over the function represented by this function pointer.
437    ///
438    /// # Examples
439    ///
440    /// ```
441    /// use rune::runtime::SyncFunction;
442    /// use rune::sync::Arc;
443    /// use rune::{Hash, Vm};
444    ///
445    /// let mut sources = rune::sources! {
446    ///     entry => {
447    ///         fn add(a, b) {
448    ///             a + b
449    ///         }
450    ///
451    ///         pub fn main() { add }
452    ///     }
453    /// };
454    ///
455    /// let unit = rune::prepare(&mut sources).build()?;
456    /// let unit = Arc::try_new(unit)?;
457    /// let mut vm = Vm::without_runtime(unit)?;
458    ///
459    /// let add = vm.call(["main"], ())?;
460    /// let add: SyncFunction = rune::from_value(add)?;
461    ///
462    /// assert_eq!(add.call::<u32>((1, 2))?, 3);
463    /// # Ok::<_, rune::support::Error>(())
464    /// ```
465    pub fn call<T>(&self, args: impl GuardedArgs) -> Result<T, VmError>
466    where
467        T: FromValue,
468    {
469        self.0.call(args)
470    }
471
472    /// Type [Hash][struct@Hash] of the underlying function.
473    ///
474    /// # Examples
475    ///
476    /// The type hash of a top-level function matches what you get out of
477    /// [Hash::type_hash].
478    ///
479    /// ```
480    /// use rune::runtime::SyncFunction;
481    /// use rune::sync::Arc;
482    /// use rune::{Hash, Vm};
483    ///
484    /// let mut sources = rune::sources! {
485    ///     entry => {
486    ///         fn pony() { }
487    ///
488    ///         pub fn main() { pony }
489    ///     }
490    /// };
491    ///
492    /// let unit = rune::prepare(&mut sources).build()?;
493    /// let unit = Arc::try_new(unit)?;
494    /// let mut vm = Vm::without_runtime(unit)?;
495    ///
496    /// let pony = vm.call(["main"], ())?;
497    /// let pony: SyncFunction = rune::from_value(pony)?;
498    ///
499    /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"]));
500    /// # Ok::<_, rune::support::Error>(())
501    /// ```
502    pub fn type_hash(&self) -> Hash {
503        self.0.type_hash()
504    }
505}
506
507impl TryClone for SyncFunction {
508    fn try_clone(&self) -> alloc::Result<Self> {
509        Ok(Self(self.0.try_clone()?))
510    }
511}
512
513/// A stored function, of some specific kind.
514struct FunctionImpl<V>
515where
516    V: FnValue,
517{
518    inner: Inner<V>,
519}
520
521impl<V> TryClone for FunctionImpl<V>
522where
523    V: FnValue,
524{
525    #[inline]
526    fn try_clone(&self) -> alloc::Result<Self> {
527        Ok(Self {
528            inner: self.inner.try_clone()?,
529        })
530    }
531}
532
533impl<V> FunctionImpl<V>
534where
535    V: FnValue,
536    OwnedTuple: TryFrom<Box<[V]>>,
537    VmErrorKind: From<<OwnedTuple as TryFrom<Box<[V]>>>::Error>,
538{
539    fn call<T>(&self, args: impl GuardedArgs) -> Result<T, VmError>
540    where
541        T: FromValue,
542    {
543        let value = match &self.inner {
544            Inner::FnHandler(handler) => {
545                let count = args.count();
546                let size = count.max(1);
547                // Ensure we have space for the return value.
548                let mut stack = Stack::with_capacity(size)?;
549                let _guard = unsafe { args.guarded_into_stack(&mut stack) }?;
550                stack.resize(size)?;
551                handler
552                    .handler
553                    .call(&mut stack, Address::ZERO, count, Address::ZERO.output())?;
554                stack.at(Address::ZERO).clone()
555            }
556            Inner::FnOffset(fn_offset) => fn_offset.call(args, ())?,
557            Inner::FnClosureOffset(closure) => {
558                let environment = closure.environment.try_clone()?;
559                let environment = OwnedTuple::try_from(environment)?;
560                closure.fn_offset.call(args, (environment,))?
561            }
562            Inner::FnUnitStruct(empty) => {
563                check_args(args.count(), 0)?;
564                Value::empty_struct(empty.rtti.clone())?
565            }
566            Inner::FnTupleStruct(tuple) => {
567                check_args(args.count(), tuple.args)?;
568                // SAFETY: We don't let the guard outlive the value.
569                let (args, _guard) = unsafe { args.guarded_into_vec()? };
570                Value::tuple_struct(tuple.rtti.clone(), args)?
571            }
572        };
573
574        Ok(T::from_value(value)?)
575    }
576
577    fn async_send_call<'a, A, T>(
578        &'a self,
579        args: A,
580    ) -> impl Future<Output = Result<T, VmError>> + Send + 'a
581    where
582        A: 'a + Send + GuardedArgs,
583        T: 'a + Send + FromValue,
584    {
585        let future = async move {
586            let value: Value = self.call(args)?;
587
588            let value = match value.try_borrow_mut::<runtime::Future>()? {
589                Some(future) => future.await?,
590                None => value,
591            };
592
593            Ok(T::from_value(value)?)
594        };
595
596        // Safety: Future is send because there is no way to call this
597        // function in a manner which allows any values from the future
598        // to escape outside of this future, hence it can only be
599        // scheduled by one thread at a time.
600        unsafe { AssertSend::new(future) }
601    }
602
603    /// Call with the given virtual machine. This allows for certain
604    /// optimizations, like avoiding the allocation of a new vm state in case
605    /// the call is internal.
606    ///
607    /// A stop reason will be returned in case the function call results in
608    /// a need to suspend the execution.
609    pub(crate) fn call_with_vm(
610        &self,
611        vm: &mut Vm,
612        addr: Address,
613        args: usize,
614        out: Output,
615    ) -> Result<Option<VmHalt>, VmError> {
616        let reason = match &self.inner {
617            Inner::FnHandler(handler) => {
618                handler.handler.call(vm.stack_mut(), addr, args, out)?;
619                None
620            }
621            Inner::FnOffset(fn_offset) => {
622                if let Some(vm_call) = fn_offset.call_with_vm(vm, addr, args, (), out)? {
623                    return Ok(Some(VmHalt::VmCall(vm_call)));
624                }
625
626                None
627            }
628            Inner::FnClosureOffset(closure) => {
629                let environment = closure.environment.try_clone()?;
630                let environment = OwnedTuple::try_from(environment)?;
631
632                if let Some(vm_call) =
633                    closure
634                        .fn_offset
635                        .call_with_vm(vm, addr, args, (environment,), out)?
636                {
637                    return Ok(Some(VmHalt::VmCall(vm_call)));
638                }
639
640                None
641            }
642            Inner::FnUnitStruct(empty) => {
643                check_args(args, 0)?;
644                vm.store(out, || Value::empty_struct(empty.rtti.clone()))?;
645                None
646            }
647            Inner::FnTupleStruct(tuple) => {
648                check_args(args, tuple.args)?;
649
650                let seq = vm.stack().slice_at(addr, args)?;
651                let data = seq.iter().cloned();
652                let value = AnySequence::new(tuple.rtti.clone(), data)?;
653                vm.store(out, value)?;
654                None
655            }
656        };
657
658        Ok(reason)
659    }
660
661    /// Create a function pointer from a handler.
662    pub(crate) fn from_handler(handler: FunctionHandler, hash: Hash) -> Self {
663        Self {
664            inner: Inner::FnHandler(FnHandler { handler, hash }),
665        }
666    }
667
668    /// Create a function pointer from an offset.
669    pub(crate) fn from_offset(
670        context: Arc<RuntimeContext>,
671        unit: Arc<Unit>,
672        globals: V::Globals,
673        offset: usize,
674        call: Call,
675        args: usize,
676        hash: Hash,
677    ) -> Self {
678        Self {
679            inner: Inner::FnOffset(FnOffset {
680                context,
681                unit,
682                globals,
683                offset,
684                call,
685                args,
686                hash,
687            }),
688        }
689    }
690
691    /// Create a function pointer from an offset.
692    pub(crate) fn from_closure(
693        context: Arc<RuntimeContext>,
694        unit: Arc<Unit>,
695        globals: V::Globals,
696        offset: usize,
697        call: Call,
698        args: usize,
699        environment: Box<[V]>,
700        hash: Hash,
701    ) -> Self {
702        Self {
703            inner: Inner::FnClosureOffset(FnClosureOffset {
704                fn_offset: FnOffset {
705                    context,
706                    unit,
707                    globals,
708                    offset,
709                    call,
710                    args,
711                    hash,
712                },
713                environment,
714            }),
715        }
716    }
717
718    /// Create a function pointer from an offset.
719    pub(crate) fn from_unit_struct(rtti: Arc<Rtti>) -> Self {
720        Self {
721            inner: Inner::FnUnitStruct(FnUnitStruct { rtti }),
722        }
723    }
724
725    /// Create a function pointer from an offset.
726    pub(crate) fn from_tuple_struct(rtti: Arc<Rtti>, args: usize) -> Self {
727        Self {
728            inner: Inner::FnTupleStruct(FnTupleStruct { rtti, args }),
729        }
730    }
731
732    #[inline]
733    fn type_hash(&self) -> Hash {
734        match &self.inner {
735            Inner::FnHandler(FnHandler { hash, .. }) | Inner::FnOffset(FnOffset { hash, .. }) => {
736                *hash
737            }
738            Inner::FnClosureOffset(fco) => fco.fn_offset.hash,
739            Inner::FnUnitStruct(func) => func.rtti.type_hash(),
740            Inner::FnTupleStruct(func) => func.rtti.type_hash(),
741        }
742    }
743}
744
745impl FunctionImpl<Value> {
746    /// Try to convert into a [SyncFunction].
747    fn into_sync(self) -> Result<FunctionImpl<ConstValueBuf>, RuntimeError> {
748        let inner = match self.inner {
749            Inner::FnClosureOffset(closure) => {
750                let mut env = Vec::try_with_capacity(closure.environment.len())?;
751
752                for value in Vec::from(closure.environment) {
753                    env.try_push(FromValue::from_value(value)?)?;
754                }
755
756                Inner::FnClosureOffset(FnClosureOffset {
757                    fn_offset: closure.fn_offset.into_sync(),
758                    environment: env.try_into_boxed_slice()?,
759                })
760            }
761            Inner::FnHandler(inner) => Inner::FnHandler(inner),
762            Inner::FnOffset(inner) => Inner::FnOffset(inner.into_sync()),
763            Inner::FnUnitStruct(inner) => Inner::FnUnitStruct(inner),
764            Inner::FnTupleStruct(inner) => Inner::FnTupleStruct(inner),
765        };
766
767        Ok(FunctionImpl { inner })
768    }
769}
770
771/// A closure holds the environment it captured, so a closure which captured
772/// another one nests just like a container does.
773impl Dismantle for Function {
774    fn dismantle(&mut self, out: &mut Handover<'_>) {
775        let Inner::FnClosureOffset(closure) = &mut self.0.inner else {
776            return;
777        };
778
779        out.consume_all(closure.environment.iter_mut());
780    }
781}
782
783impl fmt::Debug for Function {
784    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
785        match &self.0.inner {
786            Inner::FnHandler(handler) => {
787                write!(f, "native function ({:p})", handler.handler)?;
788            }
789            Inner::FnOffset(offset) => {
790                write!(f, "{} function (at: 0x{:x})", offset.call, offset.offset)?;
791            }
792            Inner::FnClosureOffset(closure) => {
793                write!(
794                    f,
795                    "closure (at: 0x{:x}, env:{:?})",
796                    closure.fn_offset.offset, closure.environment
797                )?;
798            }
799            Inner::FnUnitStruct(empty) => {
800                write!(f, "empty {}", empty.rtti.item)?;
801            }
802            Inner::FnTupleStruct(tuple) => {
803                write!(f, "tuple {}", tuple.rtti.item)?;
804            }
805        }
806
807        Ok(())
808    }
809}
810
811#[derive(Debug)]
812enum Inner<V>
813where
814    V: FnValue,
815{
816    /// A native function handler.
817    /// This is wrapped as an `Arc<dyn FunctionHandler>`.
818    FnHandler(FnHandler),
819    /// The offset to a free function.
820    ///
821    /// This also captures the context and unit it belongs to allow for external
822    /// calls.
823    FnOffset(FnOffset<V>),
824    /// A closure with a captured environment.
825    ///
826    /// This also captures the context and unit it belongs to allow for external
827    /// calls.
828    FnClosureOffset(FnClosureOffset<V>),
829    /// Constructor for a unit struct.
830    FnUnitStruct(FnUnitStruct),
831    /// Constructor for a tuple.
832    FnTupleStruct(FnTupleStruct),
833}
834
835impl<V> TryClone for Inner<V>
836where
837    V: FnValue,
838{
839    fn try_clone(&self) -> alloc::Result<Self> {
840        Ok(match self {
841            Inner::FnHandler(inner) => Inner::FnHandler(inner.clone()),
842            Inner::FnOffset(inner) => Inner::FnOffset(inner.clone()),
843            Inner::FnClosureOffset(inner) => Inner::FnClosureOffset(inner.try_clone()?),
844            Inner::FnUnitStruct(inner) => Inner::FnUnitStruct(inner.clone()),
845            Inner::FnTupleStruct(inner) => Inner::FnTupleStruct(inner.clone()),
846        })
847    }
848}
849
850#[derive(Clone, TryClone)]
851struct FnHandler {
852    /// The function handler.
853    handler: FunctionHandler,
854    /// Hash for the function type
855    hash: Hash,
856}
857
858impl fmt::Debug for FnHandler {
859    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
860        write!(f, "FnHandler")
861    }
862}
863
864/// The kind of value a function closes over, and with it the kind of static
865/// item storage the function is able to carry.
866///
867/// A [`Function`] carries the [`Globals`] of the virtual machine which produced
868/// it, so that calling it from the outside still observes the same statics. A
869/// [`SyncFunction`] can be sent between threads and the storage isn't thread
870/// safe, so it carries nothing.
871pub(crate) trait FnValue: TryClone {
872    /// How static item storage is represented for this kind of function.
873    type Globals: TryClone + Clone;
874
875    /// Materialize the storage a virtual machine should be given.
876    fn globals(globals: &Self::Globals) -> Globals;
877
878    /// Test if the given vm already uses this storage.
879    fn same_globals(globals: &Self::Globals, vm: &Vm) -> bool;
880}
881
882impl FnValue for Value {
883    type Globals = Globals;
884
885    #[inline]
886    fn globals(globals: &Self::Globals) -> Globals {
887        globals.clone()
888    }
889
890    #[inline]
891    fn same_globals(globals: &Self::Globals, vm: &Vm) -> bool {
892        vm.is_same_globals(globals)
893    }
894}
895
896impl FnValue for ConstValueBuf {
897    type Globals = ();
898
899    #[inline]
900    fn globals(_: &Self::Globals) -> Globals {
901        Globals::empty()
902    }
903
904    #[inline]
905    fn same_globals(_: &Self::Globals, vm: &Vm) -> bool {
906        !vm.globals().is_configured()
907    }
908}
909
910struct FnOffset<V>
911where
912    V: FnValue,
913{
914    context: Arc<RuntimeContext>,
915    /// The unit where the function resides.
916    unit: Arc<Unit>,
917    /// The storage for static items declared by the unit.
918    globals: V::Globals,
919    /// The offset of the function.
920    offset: usize,
921    /// The calling convention.
922    call: Call,
923    /// The number of arguments the function takes.
924    args: usize,
925    /// Hash for the function type
926    hash: Hash,
927}
928
929impl<V> Clone for FnOffset<V>
930where
931    V: FnValue,
932{
933    fn clone(&self) -> Self {
934        Self {
935            context: self.context.clone(),
936            unit: self.unit.clone(),
937            globals: self.globals.clone(),
938            offset: self.offset,
939            call: self.call,
940            args: self.args,
941            hash: self.hash,
942        }
943    }
944}
945
946impl<V> TryClone for FnOffset<V>
947where
948    V: FnValue,
949{
950    #[inline]
951    fn try_clone(&self) -> alloc::Result<Self> {
952        Ok(self.clone())
953    }
954}
955
956impl<V> FnOffset<V>
957where
958    V: FnValue,
959{
960    /// Perform a call into the specified offset and return the produced value.
961    #[tracing::instrument(skip_all, fields(args = args.count(), extra = extra.count(), ?self.offset, ?self.call, ?self.args, ?self.hash))]
962    fn call(&self, args: impl GuardedArgs, extra: impl Args) -> Result<Value, VmError> {
963        check_args(args.count().wrapping_add(extra.count()), self.args)?;
964
965        let mut vm = Vm::new(self.context.clone(), self.unit.clone())
966            .with_globals(V::globals(&self.globals));
967
968        vm.set_ip(self.offset);
969        let _guard = unsafe { args.guarded_into_stack(vm.stack_mut())? };
970        extra.into_stack(vm.stack_mut())?;
971
972        self.call.call_with_vm(vm)
973    }
974
975    /// Perform a potentially optimized call into the specified vm.
976    ///
977    /// This will cause a halt in case the vm being called into isn't the same
978    /// as the context and unit of the function.
979    #[tracing::instrument(skip_all, fields(args, extra = extra.count(), keep, ?self.offset, ?self.call, ?self.args, ?self.hash))]
980    fn call_with_vm(
981        &self,
982        vm: &mut Vm,
983        addr: Address,
984        args: usize,
985        extra: impl Args,
986        out: Output,
987    ) -> Result<Option<VmCall>, VmError> {
988        check_args(args.wrapping_add(extra.count()), self.args)?;
989
990        let same_unit = matches!(self.call, Call::Immediate if vm.is_same_unit(&self.unit));
991        let same_context =
992            matches!(self.call, Call::Immediate if vm.is_same_context(&self.context));
993        let same_globals =
994            matches!(self.call, Call::Immediate if V::same_globals(&self.globals, vm));
995
996        vm.push_call_frame(self.offset, addr, args, Isolated::new(!same_context), out)?;
997        extra.into_stack(vm.stack_mut())?;
998
999        // Fast path, just allocate a call frame and keep running.
1000        if same_context && same_unit && same_globals {
1001            tracing::trace!("same context, unit and globals");
1002            return Ok(None);
1003        }
1004
1005        let call = VmCall::new(
1006            self.call,
1007            (!same_context).then(|| self.context.clone()),
1008            (!same_unit).then(|| self.unit.clone()),
1009            (!same_globals).then(|| V::globals(&self.globals)),
1010            out,
1011        );
1012
1013        Ok(Some(call))
1014    }
1015}
1016
1017impl FnOffset<Value> {
1018    /// Shed the static item storage so that the function can be sent between
1019    /// threads.
1020    ///
1021    /// The storage isn't thread safe, so a [`SyncFunction`] cannot carry it.
1022    /// Reading a static through the resulting function reports that no storage
1023    /// has been configured.
1024    fn into_sync(self) -> FnOffset<ConstValueBuf> {
1025        FnOffset {
1026            context: self.context,
1027            unit: self.unit,
1028            globals: (),
1029            offset: self.offset,
1030            call: self.call,
1031            args: self.args,
1032            hash: self.hash,
1033        }
1034    }
1035}
1036
1037impl<V> fmt::Debug for FnOffset<V>
1038where
1039    V: FnValue,
1040{
1041    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1042        f.debug_struct("FnOffset")
1043            .field("context", &(&self.context as *const _))
1044            .field("unit", &(&self.unit as *const _))
1045            .field("offset", &self.offset)
1046            .field("call", &self.call)
1047            .field("args", &self.args)
1048            .finish()
1049    }
1050}
1051
1052#[derive(Debug)]
1053struct FnClosureOffset<V>
1054where
1055    V: FnValue,
1056{
1057    /// The offset in the associated unit that the function lives.
1058    fn_offset: FnOffset<V>,
1059    /// Captured environment.
1060    environment: Box<[V]>,
1061}
1062
1063impl<V> TryClone for FnClosureOffset<V>
1064where
1065    V: FnValue,
1066{
1067    #[inline]
1068    fn try_clone(&self) -> alloc::Result<Self> {
1069        Ok(Self {
1070            fn_offset: self.fn_offset.clone(),
1071            environment: self.environment.try_clone()?,
1072        })
1073    }
1074}
1075
1076#[derive(Debug, Clone, TryClone)]
1077struct FnUnitStruct {
1078    /// The type of the empty.
1079    rtti: Arc<Rtti>,
1080}
1081
1082#[derive(Debug, Clone, TryClone)]
1083struct FnTupleStruct {
1084    /// The type of the tuple.
1085    rtti: Arc<Rtti>,
1086    /// The number of arguments the tuple takes.
1087    args: usize,
1088}
1089
1090impl FromValue for SyncFunction {
1091    #[inline]
1092    fn from_value(value: Value) -> Result<Self, RuntimeError> {
1093        value.downcast::<Function>()?.into_sync()
1094    }
1095}
1096
1097#[inline]
1098fn check_args(actual: usize, expected: usize) -> Result<(), VmError> {
1099    if actual != expected {
1100        return Err(VmError::new(VmErrorKind::BadArgumentCount {
1101            expected,
1102            actual,
1103        }));
1104    }
1105
1106    Ok(())
1107}