mod function_meta;
mod function_traits;
pub(crate) mod module;
use core::fmt;
use core::marker::PhantomData;
use ::rust_alloc::sync::Arc;
use crate as rune;
use crate::alloc::prelude::*;
#[cfg(feature = "doc")]
use crate::alloc::Box;
use crate::alloc::{self, Vec};
use crate::compile::{meta, ContextError, Docs, Item, ItemBuf};
use crate::runtime::{
AttributeMacroHandler, ConstValue, FullTypeOf, FunctionHandler, MacroHandler, MaybeTypeOf,
StaticType, TypeCheck, TypeInfo, TypeOf,
};
use crate::Hash;
pub(crate) use self::function_meta::{AssociatedName, ToFieldFunction, ToInstance};
#[doc(hidden)]
pub use self::function_meta::{FunctionMetaData, FunctionMetaKind, MacroMetaData, MacroMetaKind};
pub use self::function_traits::{Async, Function, FunctionKind, InstanceFunction, Plain};
#[doc(hidden)]
pub use self::module::{
Module, ModuleConstantBuilder, ModuleFunctionBuilder, ModuleMeta, ModuleMetaData,
ModuleRawFunctionBuilder,
};
pub trait InstallWith {
fn install_with(_: &mut Module) -> Result<(), ContextError> {
Ok(())
}
}
pub(crate) struct InternalEnum {
pub(crate) name: &'static str,
pub(crate) static_type: &'static StaticType,
pub(crate) variants: Vec<Variant>,
}
impl InternalEnum {
fn new(name: &'static str, static_type: &'static StaticType) -> Self {
InternalEnum {
name,
static_type,
variants: Vec::new(),
}
}
fn variant<C, A>(
&mut self,
name: &'static str,
type_check: TypeCheck,
constructor: C,
) -> alloc::Result<ItemMut<'_>>
where
C: Function<A, Plain>,
{
let constructor: Arc<FunctionHandler> =
Arc::new(move |stack, args| constructor.fn_call(stack, args));
self.variants.try_push(Variant {
name,
type_check: Some(type_check),
fields: Some(Fields::Unnamed(C::args())),
constructor: Some(constructor),
#[cfg(feature = "doc")]
deprecated: None,
docs: Docs::EMPTY,
})?;
let v = self.variants.last_mut().unwrap();
Ok(ItemMut {
docs: &mut v.docs,
#[cfg(feature = "doc")]
deprecated: &mut v.deprecated,
})
}
}
pub(crate) struct ModuleType {
pub(crate) item: ItemBuf,
pub(crate) common: ModuleItemCommon,
pub(crate) hash: Hash,
pub(crate) type_parameters: Hash,
pub(crate) type_info: TypeInfo,
pub(crate) spec: Option<TypeSpecification>,
pub(crate) constructor: Option<Arc<FunctionHandler>>,
}
#[derive(Debug)]
pub(crate) enum Fields {
Named(&'static [&'static str]),
Unnamed(usize),
Empty,
}
pub struct Variant {
pub(crate) name: &'static str,
pub(crate) type_check: Option<TypeCheck>,
pub(crate) fields: Option<Fields>,
pub(crate) constructor: Option<Arc<FunctionHandler>>,
#[cfg(feature = "doc")]
pub(crate) deprecated: Option<Box<str>>,
pub(crate) docs: Docs,
}
impl Variant {
fn new(name: &'static str) -> Self {
Self {
name,
type_check: None,
fields: None,
constructor: None,
#[cfg(feature = "doc")]
deprecated: None,
docs: Docs::EMPTY,
}
}
}
impl fmt::Debug for Variant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut f = f.debug_struct("Variant");
f.field("fields", &self.fields);
f.field("constructor", &self.constructor.is_some());
#[cfg(feature = "doc")]
f.field("deprecated", &self.deprecated);
f.field("docs", &self.docs);
f.finish()
}
}
pub(crate) struct Enum {
pub(crate) variants: Vec<Variant>,
}
pub(crate) enum TypeSpecification {
Struct(Fields),
Enum(Enum),
}
#[derive(Debug, TryClone, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub(crate) struct AssociatedKey {
pub(crate) type_hash: Hash,
pub(crate) kind: meta::AssociatedKind,
pub(crate) parameters: Hash,
}
pub(crate) enum ModuleItemKind {
Constant(ConstValue),
Function(ModuleFunction),
Macro(ModuleMacro),
AttributeMacro(ModuleAttributeMacro),
InternalEnum(InternalEnum),
}
pub(crate) struct ModuleItem {
pub(crate) item: ItemBuf,
pub(crate) common: ModuleItemCommon,
pub(crate) kind: ModuleItemKind,
}
#[derive(TryClone)]
pub(crate) struct ModuleFunction {
pub(crate) handler: Arc<FunctionHandler>,
#[cfg(feature = "doc")]
pub(crate) is_async: bool,
#[cfg(feature = "doc")]
pub(crate) args: Option<usize>,
#[cfg(feature = "doc")]
pub(crate) return_type: Option<FullTypeOf>,
#[cfg(feature = "doc")]
pub(crate) argument_types: Box<[Option<FullTypeOf>]>,
}
#[derive(TryClone)]
pub(crate) enum ModuleAssociatedKind {
Constant(ConstValue),
Function(ModuleFunction),
}
#[derive(Default, TryClone)]
pub(crate) struct ModuleItemCommon {
pub(crate) docs: Docs,
#[cfg(feature = "doc")]
pub(crate) deprecated: Option<Box<str>>,
}
#[derive(TryClone)]
pub(crate) struct ModuleAssociated {
pub(crate) container: FullTypeOf,
pub(crate) container_type_info: TypeInfo,
pub(crate) name: AssociatedName,
pub(crate) common: ModuleItemCommon,
pub(crate) kind: ModuleAssociatedKind,
}
pub(crate) struct ModuleMacro {
pub(crate) handler: Arc<MacroHandler>,
}
pub(crate) struct ModuleAttributeMacro {
pub(crate) handler: Arc<AttributeMacroHandler>,
}
pub struct ItemMut<'a> {
docs: &'a mut Docs,
#[cfg(feature = "doc")]
deprecated: &'a mut Option<Box<str>>,
}
impl ItemMut<'_> {
pub fn docs<I>(self, docs: I) -> Result<Self, ContextError>
where
I: IntoIterator,
I::Item: AsRef<str>,
{
self.docs.set_docs(docs)?;
Ok(self)
}
pub fn static_docs(self, docs: &'static [&'static str]) -> Result<Self, ContextError> {
self.docs.set_docs(docs)?;
Ok(self)
}
pub fn deprecated<S>(
self,
#[cfg_attr(not(feature = "doc"), allow(unused))] deprecated: S,
) -> Result<Self, ContextError>
where
S: AsRef<str>,
{
#[cfg(feature = "doc")]
{
*self.deprecated = Some(deprecated.as_ref().try_into()?);
}
Ok(self)
}
}
impl fmt::Debug for ItemMut<'_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ItemMut").finish_non_exhaustive()
}
}
pub struct ItemFnMut<'a> {
docs: &'a mut Docs,
#[cfg(feature = "doc")]
deprecated: &'a mut Option<Box<str>>,
#[cfg(feature = "doc")]
is_async: &'a mut bool,
#[cfg(feature = "doc")]
args: &'a mut Option<usize>,
#[cfg(feature = "doc")]
return_type: &'a mut Option<FullTypeOf>,
#[cfg(feature = "doc")]
argument_types: &'a mut Box<[Option<FullTypeOf>]>,
}
impl ItemFnMut<'_> {
pub fn docs<I>(self, docs: I) -> Result<Self, ContextError>
where
I: IntoIterator,
I::Item: AsRef<str>,
{
self.docs.set_docs(docs)?;
Ok(self)
}
pub fn is_async(self, #[cfg_attr(not(feature = "doc"), allow(unused))] is_async: bool) -> Self {
#[cfg(feature = "doc")]
{
*self.is_async = is_async;
}
self
}
pub fn deprecated<S>(
self,
#[cfg_attr(not(feature = "doc"), allow(unused))] deprecated: S,
) -> Result<Self, ContextError>
where
S: AsRef<str>,
{
#[cfg(feature = "doc")]
{
*self.deprecated = Some(deprecated.as_ref().try_into()?);
}
Ok(self)
}
pub fn args(self, #[cfg_attr(not(feature = "doc"), allow(unused))] args: usize) -> Self {
#[cfg(feature = "doc")]
{
*self.args = Some(args);
}
self
}
pub fn return_type<T>(self) -> Self
where
T: MaybeTypeOf,
{
#[cfg(feature = "doc")]
{
*self.return_type = T::maybe_type_of();
}
self
}
pub fn argument_types<const N: usize>(
self,
#[cfg_attr(not(feature = "doc"), allow(unused))] arguments: [Option<FullTypeOf>; N],
) -> Result<Self, ContextError> {
#[cfg(feature = "doc")]
{
*self.argument_types = arguments.into_iter().try_collect::<Box<[_]>>()?;
}
Ok(self)
}
}
impl fmt::Debug for ItemFnMut<'_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ItemMut").finish_non_exhaustive()
}
}
pub struct VariantMut<'a, T>
where
T: ?Sized + TypeOf,
{
pub(crate) index: usize,
pub(crate) docs: &'a mut Docs,
pub(crate) fields: &'a mut Option<Fields>,
pub(crate) constructor: &'a mut Option<Arc<FunctionHandler>>,
pub(crate) _marker: PhantomData<T>,
}
impl<T> VariantMut<'_, T>
where
T: ?Sized + TypeOf,
{
pub fn docs<I>(self, docs: I) -> Result<Self, ContextError>
where
I: IntoIterator,
I::Item: AsRef<str>,
{
self.docs.set_docs(docs)?;
Ok(self)
}
pub fn static_docs(self, docs: &'static [&'static str]) -> Result<Self, ContextError> {
self.docs.set_docs(docs)?;
Ok(self)
}
pub fn make_named(self, fields: &'static [&'static str]) -> Result<Self, ContextError> {
self.make(Fields::Named(fields))
}
pub fn make_unnamed(self, fields: usize) -> Result<Self, ContextError> {
self.make(Fields::Unnamed(fields))
}
pub fn make_empty(self) -> Result<Self, ContextError> {
self.make(Fields::Empty)
}
pub fn constructor<F, A>(self, constructor: F) -> Result<Self, ContextError>
where
F: Function<A, Plain, Return = T>,
{
if self.constructor.is_some() {
return Err(ContextError::VariantConstructorConflict {
type_info: T::type_info(),
index: self.index,
});
}
*self.constructor = Some(Arc::new(move |stack, args| {
constructor.fn_call(stack, args)
}));
Ok(self)
}
fn make(self, fields: Fields) -> Result<Self, ContextError> {
let old = self.fields.replace(fields);
if old.is_some() {
return Err(ContextError::ConflictingVariantMeta {
index: self.index,
type_info: T::type_info(),
});
}
Ok(self)
}
}
pub struct EnumMut<'a, T>
where
T: ?Sized + TypeOf,
{
docs: &'a mut Docs,
enum_: &'a mut Enum,
_marker: PhantomData<T>,
}
impl<T> EnumMut<'_, T>
where
T: ?Sized + TypeOf,
{
pub fn docs<I>(self, docs: I) -> Result<Self, ContextError>
where
I: IntoIterator,
I::Item: AsRef<str>,
{
self.docs.set_docs(docs)?;
Ok(self)
}
pub fn static_docs(self, docs: &'static [&'static str]) -> Result<Self, ContextError> {
self.docs.set_docs(docs)?;
Ok(self)
}
pub fn variant_mut(&mut self, index: usize) -> Result<VariantMut<'_, T>, ContextError> {
let Some(variant) = self.enum_.variants.get_mut(index) else {
return Err(ContextError::MissingVariant {
index,
type_info: T::type_info(),
});
};
Ok(VariantMut {
index,
docs: &mut variant.docs,
fields: &mut variant.fields,
constructor: &mut variant.constructor,
_marker: PhantomData,
})
}
}
pub struct InternalEnumMut<'a, T>
where
T: ?Sized + TypeOf,
{
enum_: &'a mut InternalEnum,
common: &'a mut ModuleItemCommon,
_marker: PhantomData<T>,
}
impl<T> InternalEnumMut<'_, T>
where
T: ?Sized + TypeOf,
{
pub fn docs<I>(self, docs: I) -> Result<Self, ContextError>
where
I: IntoIterator,
I::Item: AsRef<str>,
{
self.common.docs.set_docs(docs)?;
Ok(self)
}
pub fn static_docs(self, docs: &'static [&'static str]) -> Result<Self, ContextError> {
self.common.docs.set_docs(docs)?;
Ok(self)
}
pub fn deprecated<S>(
self,
#[cfg_attr(not(feature = "doc"), allow(unused))] deprecated: S,
) -> Result<Self, ContextError>
where
S: AsRef<str>,
{
#[cfg(feature = "doc")]
{
self.common.deprecated = Some(deprecated.as_ref().try_into()?);
}
Ok(self)
}
pub fn variant_mut(&mut self, index: usize) -> Result<VariantMut<'_, T>, ContextError> {
let Some(variant) = self.enum_.variants.get_mut(index) else {
return Err(ContextError::MissingVariant {
index,
type_info: T::type_info(),
});
};
Ok(VariantMut {
index,
docs: &mut variant.docs,
fields: &mut variant.fields,
constructor: &mut variant.constructor,
_marker: PhantomData,
})
}
}
pub struct TypeMut<'a, T>
where
T: ?Sized + TypeOf,
{
docs: &'a mut Docs,
#[cfg(feature = "doc")]
deprecated: &'a mut Option<Box<str>>,
spec: &'a mut Option<TypeSpecification>,
constructor: &'a mut Option<Arc<FunctionHandler>>,
item: &'a Item,
_marker: PhantomData<T>,
}
impl<'a, T> TypeMut<'a, T>
where
T: ?Sized + TypeOf,
{
pub fn docs<I>(self, docs: I) -> Result<Self, ContextError>
where
I: IntoIterator,
I::Item: AsRef<str>,
{
self.docs.set_docs(docs)?;
Ok(self)
}
pub fn static_docs(self, docs: &'static [&'static str]) -> Result<Self, ContextError> {
self.docs.set_docs(docs)?;
Ok(self)
}
pub fn deprecated<S>(
self,
#[cfg_attr(not(feature = "doc"), allow(unused))] deprecated: S,
) -> Result<Self, ContextError>
where
S: AsRef<str>,
{
#[cfg(feature = "doc")]
{
*self.deprecated = Some(deprecated.as_ref().try_into()?);
}
Ok(self)
}
pub fn make_named_struct(self, fields: &'static [&'static str]) -> Result<Self, ContextError> {
self.make_struct(Fields::Named(fields))
}
pub fn make_unnamed_struct(self, fields: usize) -> Result<Self, ContextError> {
self.make_struct(Fields::Unnamed(fields))
}
pub fn make_empty_struct(self) -> Result<Self, ContextError> {
self.make_struct(Fields::Empty)
}
pub fn make_enum(
self,
variants: &'static [&'static str],
) -> Result<EnumMut<'a, T>, ContextError> {
let old = self.spec.replace(TypeSpecification::Enum(Enum {
variants: variants.iter().copied().map(Variant::new).try_collect()?,
}));
if old.is_some() {
return Err(ContextError::ConflictingTypeMeta {
item: self.item.try_to_owned()?,
type_info: T::type_info(),
});
}
let Some(TypeSpecification::Enum(enum_)) = self.spec.as_mut() else {
panic!("Not an enum");
};
Ok(EnumMut {
docs: self.docs,
enum_,
_marker: PhantomData,
})
}
pub fn constructor<F, A>(self, constructor: F) -> Result<Self, ContextError>
where
F: Function<A, Plain, Return = T>,
{
if self.constructor.is_some() {
return Err(ContextError::ConstructorConflict {
type_info: T::type_info(),
});
}
*self.constructor = Some(Arc::new(move |stack, args| {
constructor.fn_call(stack, args)
}));
Ok(self)
}
fn make_struct(self, fields: Fields) -> Result<Self, ContextError> {
let old = self.spec.replace(TypeSpecification::Struct(fields));
if old.is_some() {
return Err(ContextError::ConflictingTypeMeta {
item: self.item.try_to_owned()?,
type_info: T::type_info(),
});
}
Ok(self)
}
}
impl<T> fmt::Debug for TypeMut<'_, T>
where
T: TypeOf,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TypeMut").finish_non_exhaustive()
}
}