rune/module/
variant_mut.rs

1use core::marker::PhantomData;
2
3use ::rust_alloc::sync::Arc;
4
5use crate::compile::{ContextError, Docs};
6use crate::function::{Function, Plain};
7use crate::runtime::{FunctionHandler, TypeOf};
8
9use super::Fields;
10
11/// Handle to a a variant inserted into a module which allows for mutation of
12/// its metadata.
13pub struct VariantMut<'a, T>
14where
15    T: ?Sized + TypeOf,
16{
17    pub(crate) name: &'static str,
18    pub(crate) docs: &'a mut Docs,
19    pub(crate) fields: &'a mut Option<Fields>,
20    pub(crate) constructor: &'a mut Option<Arc<FunctionHandler>>,
21    pub(crate) _marker: PhantomData<T>,
22}
23
24impl<T> VariantMut<'_, T>
25where
26    T: ?Sized + TypeOf,
27{
28    /// Set documentation for an inserted type.
29    ///
30    /// This completely replaces any existing documentation.
31    pub fn docs<I>(self, docs: I) -> Result<Self, ContextError>
32    where
33        I: IntoIterator,
34        I::Item: AsRef<str>,
35    {
36        self.docs.set_docs(docs)?;
37        Ok(self)
38    }
39
40    /// Set static documentation.
41    ///
42    /// This completely replaces any existing documentation.
43    pub fn static_docs(self, docs: &'static [&'static str]) -> Result<Self, ContextError> {
44        self.docs.set_docs(docs)?;
45        Ok(self)
46    }
47
48    /// Mark the given variant with named fields.
49    pub fn make_named(self, fields: &'static [&'static str]) -> Result<Self, ContextError> {
50        self.make(Fields::Named(fields))
51    }
52
53    /// Mark the given variant with unnamed fields.
54    pub fn make_unnamed(self, fields: usize) -> Result<Self, ContextError> {
55        self.make(Fields::Unnamed(fields))
56    }
57
58    /// Mark the given variant as empty.
59    pub fn make_empty(self) -> Result<Self, ContextError> {
60        self.make(Fields::Empty)
61    }
62
63    /// Register a constructor method for the current variant.
64    pub fn constructor<F, A>(self, constructor: F) -> Result<Self, ContextError>
65    where
66        F: Function<A, Plain, Return = T>,
67    {
68        if self.constructor.is_some() {
69            return Err(ContextError::VariantConstructorConflict {
70                type_info: T::type_info(),
71                name: self.name,
72            });
73        }
74
75        *self.constructor = Some(Arc::new(move |stack, addr, args, output| {
76            constructor.fn_call(stack, addr, args, output)
77        }));
78
79        Ok(self)
80    }
81
82    fn make(self, fields: Fields) -> Result<Self, ContextError> {
83        let old = self.fields.replace(fields);
84
85        if old.is_some() {
86            return Err(ContextError::ConflictingVariantMeta {
87                type_info: T::type_info(),
88                name: self.name,
89            });
90        }
91
92        Ok(self)
93    }
94}