use std::{
cmp::Ordering,
fmt::{Debug, Display, Formatter},
hash::Hash,
};
use crate::runtime::{InvocationMeta, PackageMeta, RustIdent, TypeFamily, TypeMeta};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum TypeHint {
Type(&'static TypeMeta),
Family(&'static TypeFamily),
Invocation(&'static InvocationMeta),
}
impl Display for TypeHint {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Type(meta) => {
if formatter.alternate() || meta.is_fn() {
return Display::fmt(meta, formatter);
}
Display::fmt(meta.family(), formatter)
}
Self::Family(meta) => Display::fmt(meta, formatter),
Self::Invocation(meta) => Display::fmt(meta, formatter),
}
}
}
impl From<&'static TypeMeta> for TypeHint {
#[inline(always)]
fn from(value: &'static TypeMeta) -> Self {
Self::Type(value)
}
}
impl From<&'static TypeFamily> for TypeHint {
#[inline(always)]
fn from(value: &'static TypeFamily) -> Self {
Self::Family(value)
}
}
impl From<&'static InvocationMeta> for TypeHint {
#[inline(always)]
fn from(value: &'static InvocationMeta) -> Self {
Self::Invocation(value)
}
}
impl TypeHint {
#[inline(always)]
pub fn nil() -> Self {
Self::Type(TypeMeta::nil())
}
#[inline(always)]
pub fn dynamic() -> Self {
Self::Type(TypeMeta::dynamic())
}
#[inline(always)]
pub fn is_nil(&self) -> bool {
self.type_family().is_nil()
}
#[inline(always)]
pub fn is_dynamic(&self) -> bool {
self.type_family().is_dynamic()
}
#[inline(always)]
pub fn is_fn(&self) -> bool {
match self {
Self::Type(meta) => meta.is_fn(),
Self::Family(meta) => meta.is_fn(),
Self::Invocation(_) => true,
}
}
#[inline(always)]
pub fn is_package(&self) -> bool {
match self {
Self::Type(meta) => meta.family().is_package(),
Self::Family(meta) => meta.is_package(),
Self::Invocation(_) => false,
}
}
#[inline(always)]
pub fn is_number(&self) -> bool {
match self {
Self::Type(meta) => meta.family().is_number(),
Self::Family(meta) => meta.is_number(),
Self::Invocation(_) => false,
}
}
#[inline(always)]
pub fn type_meta(&self) -> Option<&'static TypeMeta> {
match self {
Self::Type(meta) => Some(*meta),
Self::Family(_) => None,
Self::Invocation(meta) => {
let arity = meta.arity()?;
TypeMeta::script_fn(arity)
}
}
}
#[inline(always)]
pub fn type_family(&self) -> &'static TypeFamily {
match self {
Self::Type(meta) => meta.family(),
Self::Family(meta) => *meta,
Self::Invocation(_) => TypeFamily::fn_family(),
}
}
#[inline(always)]
pub fn invocation(&self) -> Option<&'static InvocationMeta> {
match self {
Self::Type(meta) => meta.prototype().hint_invocation(),
Self::Family(_) => None,
Self::Invocation(meta) => Some(meta),
}
}
#[inline(always)]
pub fn package(&self) -> Option<&'static PackageMeta> {
match self {
Self::Type(meta) => meta.origin().package(),
Self::Family(_) => None,
Self::Invocation(meta) => meta.origin.package(),
}
}
#[inline(always)]
pub fn doc(&self) -> Option<&'static str> {
match self {
Self::Type(meta) => {
let family = meta.family();
if family.len() > 1 && !family.is_package() {
return family.doc();
}
meta.doc()
}
Self::Family(meta) => meta.doc(),
Self::Invocation(meta) => meta.doc,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ComponentHint {
pub name: &'static RustIdent,
pub ty: TypeHint,
pub doc: Option<&'static str>,
}
impl Display for ComponentHint {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
formatter.write_str(self.name.as_ref())?;
if !self.ty.is_dynamic() {
formatter.write_str(": ")?;
Display::fmt(&self.ty, formatter)?;
}
Ok(())
}
}
impl PartialOrd for ComponentHint {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ComponentHint {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.name.cmp(&other.name)
}
}