use std::{
fmt::{Display, Formatter},
hash::{Hash, Hasher},
mem::take,
};
use crate::{
report::system_panic,
runtime::{Cell, Ident, Origin, Provider, TypeHint},
};
#[derive(Clone, Debug)]
pub struct InvocationMeta {
pub origin: Origin,
pub name: Option<&'static str>,
pub doc: Option<&'static str>,
pub receiver: Option<TypeHint>,
pub inputs: Option<Vec<Param>>,
pub output: TypeHint,
}
impl PartialEq for &'static InvocationMeta {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self as *const Self as usize == other as *const Self as usize
}
}
impl Eq for &'static InvocationMeta {}
impl Hash for &'static InvocationMeta {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) {
(self as *const Self as usize).hash(state)
}
}
impl Display for InvocationMeta {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match (&self.receiver, self.name) {
(None, Some(name)) => formatter.write_str(&format!("fn {}", name))?,
(Some(ty), Some(name)) => formatter.write_str(&format!("{}::{}", ty, name))?,
_ => formatter.write_str("fn")?,
};
if let Some(parameters) = &self.inputs {
formatter.write_str("(")?;
let mut is_first = true;
for parameter in parameters {
match is_first {
true => is_first = false,
false => formatter.write_str(", ")?,
}
Display::fmt(parameter, formatter)?;
}
formatter.write_str(")")?;
}
if !self.output.is_nil() {
formatter.write_str(" -> ")?;
Display::fmt(&self.output, formatter)?;
}
Ok(())
}
}
impl InvocationMeta {
#[inline(always)]
pub fn new(origin: Origin) -> Self {
Self {
origin,
name: None,
doc: None,
receiver: None,
inputs: None,
output: TypeHint::dynamic(),
}
}
#[inline(always)]
pub fn arity(&self) -> Option<usize> {
self.inputs.as_ref().map(|inputs| inputs.len())
}
}
#[derive(Clone, Debug)]
pub struct Param {
pub name: Option<Ident>,
pub hint: TypeHint,
}
impl Display for Param {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match self.hint.is_dynamic() {
true => match &self.name {
None => formatter.write_str("_"),
Some(name) => formatter.write_fmt(format_args!("{name}")),
},
false => {
if let Some(name) = &self.name {
formatter.write_fmt(format_args!("{name}: "))?;
}
formatter.write_fmt(format_args!("{}", self.hint))
}
}
}
}
#[derive(Clone, Default)]
pub struct Arg {
pub origin: Origin,
pub data: Cell,
}
impl Arg {
#[inline(always)]
pub fn new(origin: Origin, data: Cell) -> Self {
Self { origin, data }
}
#[inline(always)]
pub fn provider(&mut self) -> Provider {
Provider::Borrowed(&mut self.data)
}
#[inline(always)]
pub fn into_provider<'a>(self) -> Provider<'a> {
Provider::Owned(self.data)
}
#[inline(always)]
pub fn split(self) -> (Origin, Cell) {
(self.origin, self.data)
}
#[inline(always)]
pub fn take(arguments: &mut [Self], index: usize) -> Self {
take(&mut arguments[index])
}
#[inline(always)]
pub unsafe fn take_unchecked(arguments: &mut [Self], index: usize) -> Self {
#[cfg(debug_assertions)]
{
if index >= arguments.len() {
let bounds = arguments.len();
system_panic!("Argument {index} index out of bounds({bounds}).",);
}
}
take(unsafe { arguments.get_unchecked_mut(index) })
}
}