diff --git a/src/api/type_names.rs b/src/api/type_names.rs index de9120ac..495916ed 100644 --- a/src/api/type_names.rs +++ b/src/api/type_names.rs @@ -106,6 +106,71 @@ fn map_std_type_name(name: &str, shorthands: bool) -> &str { .map_or(name, |s| map_std_type_name(s, shorthands)) } +/// Format a Rust type to be display-friendly. +/// +/// * `()` is cleared. +/// * `INT` and `FLOAT` are expanded. +/// * [`RhaiResult`][crate::RhaiResult] and [`RhaiResultOf`][crate::RhaiResultOf] are expanded. +#[cfg(feature = "metadata")] +pub fn format_type(typ: &str, is_return_type: bool) -> std::borrow::Cow { + const RHAI_RESULT_TYPE: &str = "RhaiResult"; + const RHAI_RESULT_TYPE_EXPAND: &str = "Result>"; + const RHAI_RESULT_OF_TYPE: &str = "RhaiResultOf<"; + const RHAI_RESULT_OF_TYPE_EXPAND: &str = "Result<{}, Box>"; + const RHAI_RANGE: &str = "ExclusiveRange"; + const RHAI_RANGE_TYPE: &str = "Range<"; + const RHAI_RANGE_EXPAND: &str = "Range<{}>"; + const RHAI_INCLUSIVE_RANGE: &str = "InclusiveRange"; + const RHAI_INCLUSIVE_RANGE_TYPE: &str = "RangeInclusive<"; + const RHAI_INCLUSIVE_RANGE_EXPAND: &str = "RangeInclusive<{}>"; + + let typ = typ.trim(); + + if let Some(x) = typ.strip_prefix("rhai::") { + return format_type(x, is_return_type); + } else if let Some(x) = typ.strip_prefix("&mut ") { + let r = format_type(x, false); + return if r == x { + typ.into() + } else { + format!("&mut {r}").into() + }; + } + + match typ { + "" | "()" if is_return_type => "".into(), + "INT" => std::any::type_name::().into(), + #[cfg(not(feature = "no_float"))] + "FLOAT" => std::any::type_name::().into(), + RHAI_RANGE => RHAI_RANGE_EXPAND + .replace("{}", std::any::type_name::()) + .into(), + RHAI_INCLUSIVE_RANGE => RHAI_INCLUSIVE_RANGE_EXPAND + .replace("{}", std::any::type_name::()) + .into(), + RHAI_RESULT_TYPE => RHAI_RESULT_TYPE_EXPAND.into(), + ty if ty.starts_with(RHAI_RANGE_TYPE) && ty.ends_with('>') => { + let inner = &ty[RHAI_RANGE_TYPE.len()..ty.len() - 1]; + RHAI_RANGE_EXPAND + .replace("{}", format_type(inner, false).trim()) + .into() + } + ty if ty.starts_with(RHAI_INCLUSIVE_RANGE_TYPE) && ty.ends_with('>') => { + let inner = &ty[RHAI_INCLUSIVE_RANGE_TYPE.len()..ty.len() - 1]; + RHAI_INCLUSIVE_RANGE_EXPAND + .replace("{}", format_type(inner, false).trim()) + .into() + } + ty if ty.starts_with(RHAI_RESULT_OF_TYPE) && ty.ends_with('>') => { + let inner = &ty[RHAI_RESULT_OF_TYPE.len()..ty.len() - 1]; + RHAI_RESULT_OF_TYPE_EXPAND + .replace("{}", format_type(inner, false).trim()) + .into() + } + ty => ty.into(), + } +} + impl Engine { /// Pretty-print a type name. /// diff --git a/src/module/mod.rs b/src/module/mod.rs index 16a10dfa..435d6cdd 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -1,5 +1,6 @@ //! Module defining external-loaded modules for Rhai. +use crate::api::type_names::format_type; use crate::ast::FnAccess; use crate::func::{ shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, RegisterNativeFunction, @@ -116,69 +117,6 @@ pub struct FuncInfo { } impl FuncInfo { - /// Format a return type to be display-friendly. - /// - /// `()` is cleared. - /// [`RhaiResult`][crate::RhaiResult] and [`RhaiResultOf`] are expanded. - #[cfg(feature = "metadata")] - pub fn format_type(typ: &str, is_return_type: bool) -> std::borrow::Cow { - const RHAI_RESULT_TYPE: &str = "RhaiResult"; - const RHAI_RESULT_TYPE_EXPAND: &str = "Result>"; - const RHAI_RESULT_OF_TYPE: &str = "RhaiResultOf<"; - const RHAI_RESULT_OF_TYPE_EXPAND: &str = "Result<{}, Box>"; - const RHAI_RANGE: &str = "ExclusiveRange"; - const RHAI_RANGE_TYPE: &str = "Range<"; - const RHAI_RANGE_EXPAND: &str = "Range<{}>"; - const RHAI_INCLUSIVE_RANGE: &str = "InclusiveRange"; - const RHAI_INCLUSIVE_RANGE_TYPE: &str = "RangeInclusive<"; - const RHAI_INCLUSIVE_RANGE_EXPAND: &str = "RangeInclusive<{}>"; - - let typ = typ.trim(); - - if let Some(x) = typ.strip_prefix("rhai::") { - return Self::format_type(x, is_return_type); - } else if let Some(x) = typ.strip_prefix("&mut ") { - let r = Self::format_type(x, false); - return if r == x { - typ.into() - } else { - format!("&mut {r}").into() - }; - } - - match typ { - "" | "()" if is_return_type => "".into(), - "INT" => std::any::type_name::().into(), - #[cfg(not(feature = "no_float"))] - "FLOAT" => std::any::type_name::().into(), - RHAI_RANGE => RHAI_RANGE_EXPAND - .replace("{}", std::any::type_name::()) - .into(), - RHAI_INCLUSIVE_RANGE => RHAI_INCLUSIVE_RANGE_EXPAND - .replace("{}", std::any::type_name::()) - .into(), - RHAI_RESULT_TYPE => RHAI_RESULT_TYPE_EXPAND.into(), - ty if ty.starts_with(RHAI_RANGE_TYPE) && ty.ends_with('>') => { - let inner = &ty[RHAI_RANGE_TYPE.len()..ty.len() - 1]; - RHAI_RANGE_EXPAND - .replace("{}", Self::format_type(inner, false).trim()) - .into() - } - ty if ty.starts_with(RHAI_INCLUSIVE_RANGE_TYPE) && ty.ends_with('>') => { - let inner = &ty[RHAI_INCLUSIVE_RANGE_TYPE.len()..ty.len() - 1]; - RHAI_INCLUSIVE_RANGE_EXPAND - .replace("{}", Self::format_type(inner, false).trim()) - .into() - } - ty if ty.starts_with(RHAI_RESULT_OF_TYPE) && ty.ends_with('>') => { - let inner = &ty[RHAI_RESULT_OF_TYPE.len()..ty.len() - 1]; - RHAI_RESULT_OF_TYPE_EXPAND - .replace("{}", Self::format_type(inner, false).trim()) - .into() - } - ty => ty.into(), - } - } /// _(metadata)_ Generate a signature of the function. /// Exported under the `metadata` feature only. #[cfg(feature = "metadata")] @@ -186,7 +124,7 @@ impl FuncInfo { pub fn gen_signature(&self) -> String { let mut sig = format!("{}(", self.metadata.name); - let return_type = Self::format_type(&self.metadata.return_type, true); + let return_type = format_type(&self.metadata.return_type, true); if self.metadata.params_info.is_empty() { for x in 0..self.metadata.params { @@ -207,9 +145,7 @@ impl FuncInfo { s => s, }; let result: std::borrow::Cow = match seg.next() { - Some(typ) => { - format!("{name}: {}", FuncInfo::format_type(typ, false)).into() - } + Some(typ) => format!("{name}: {}", format_type(typ, false)).into(), None => name.into(), }; result diff --git a/src/serde/metadata.rs b/src/serde/metadata.rs index 7a562d5c..b693c858 100644 --- a/src/serde/metadata.rs +++ b/src/serde/metadata.rs @@ -1,6 +1,7 @@ //! Serialization of functions metadata. #![cfg(feature = "metadata")] +use crate::api::type_names::format_type; use crate::module::{calc_native_fn_hash, FuncInfo}; use crate::{calc_fn_hash, Engine, FnAccess, SmartString, StaticVec, AST}; use serde::Serialize; @@ -94,12 +95,12 @@ impl<'a> From<&'a FuncInfo> for FnMetadata<'a> { "_" => None, s => Some(s), }; - let typ = seg.next().map(|s| FuncInfo::format_type(s, false)); + let typ = seg.next().map(|s| format_type(s, false)); FnParam { name, typ } }) .collect(), _dummy: None, - return_type: FuncInfo::format_type(&info.metadata.return_type, true), + return_type: format_type(&info.metadata.return_type, true), signature: info.gen_signature().into(), doc_comments: if info.func.is_script() { #[cfg(feature = "no_function")]