use std::sync::Arc;
use foundry_compilers::artifacts::{
ast::SourceLocation, FunctionDefinition, FunctionTypeName, ModifierDefinition, StateMutability,
Visibility,
};
use once_cell::sync::OnceCell;
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use serde::{Deserialize, Serialize};
use crate::analysis::{macros::universal_id, ContractRef, StepRef};
universal_id! {
UFID => 0
}
#[derive(Debug, Clone)]
pub struct FunctionRef {
inner: Arc<RwLock<Function>>,
ufid: OnceCell<UFID>,
contract: OnceCell<Option<ContractRef>>,
}
impl From<Function> for FunctionRef {
fn from(function: Function) -> Self {
Self::new(function)
}
}
impl FunctionRef {
pub fn new(inner: Function) -> Self {
Self {
inner: Arc::new(RwLock::new(inner)),
ufid: OnceCell::new(),
contract: OnceCell::new(),
}
}
}
impl FunctionRef {
pub(crate) fn read(&self) -> RwLockReadGuard<'_, Function> {
self.inner.read()
}
pub(crate) fn write(&self) -> RwLockWriteGuard<'_, Function> {
self.inner.write()
}
}
impl FunctionRef {
pub fn ufid(&self) -> UFID {
*self.ufid.get_or_init(|| self.inner.read().ufid)
}
pub fn contract(&self) -> Option<ContractRef> {
self.contract.get_or_init(|| self.inner.read().contract.clone()).clone()
}
pub fn name(&self) -> String {
self.read().definition.name().to_string()
}
pub fn visibility(&self) -> Visibility {
self.read().definition.visibility().clone()
}
pub fn state_mutability(&self) -> Option<StateMutability> {
self.read().definition.state_mutability().cloned()
}
pub fn src(&self) -> SourceLocation {
*self.read().definition.src()
}
}
impl Serialize for FunctionRef {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.read().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for FunctionRef {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let function = Function::deserialize(deserializer)?;
Ok(Self::new(function))
}
}
#[derive(Debug, Clone)]
pub struct FunctionTypeNameRef {
inner: Arc<RwLock<FunctionTypeName>>,
}
impl From<FunctionTypeName> for FunctionTypeNameRef {
fn from(function_type: FunctionTypeName) -> Self {
Self::new(function_type)
}
}
impl FunctionTypeNameRef {
pub fn new(inner: FunctionTypeName) -> Self {
Self { inner: Arc::new(RwLock::new(inner)) }
}
}
#[allow(unused)]
impl FunctionTypeNameRef {
pub(crate) fn read(&self) -> RwLockReadGuard<'_, FunctionTypeName> {
self.inner.read()
}
pub(crate) fn write(&self) -> RwLockWriteGuard<'_, FunctionTypeName> {
self.inner.write()
}
}
impl FunctionTypeNameRef {
pub fn visibility(&self) -> Visibility {
self.read().visibility.clone()
}
pub fn state_mutability(&self) -> StateMutability {
self.read().state_mutability.clone()
}
pub fn src(&self) -> SourceLocation {
self.read().src
}
}
impl Serialize for FunctionTypeNameRef {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.read().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for FunctionTypeNameRef {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let function_type = FunctionTypeName::deserialize(deserializer)?;
Ok(Self::new(function_type))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Function {
pub ufid: UFID,
pub contract: Option<ContractRef>,
pub definition: FunctionVariant,
pub steps: Vec<StepRef>,
}
#[derive(Debug, Clone, Serialize, Deserialize, derive_more::From)]
pub enum FunctionVariant {
Function(#[from] FunctionDefinition),
Modifier(#[from] ModifierDefinition),
}
impl FunctionVariant {
pub fn name(&self) -> &str {
match self {
Self::Function(definition) => &definition.name,
Self::Modifier(definition) => &definition.name,
}
}
pub fn visibility(&self) -> &Visibility {
match self {
Self::Function(definition) => &definition.visibility,
Self::Modifier(definition) => &definition.visibility,
}
}
pub fn src(&self) -> &SourceLocation {
match self {
Self::Function(definition) => &definition.src,
Self::Modifier(definition) => &definition.src,
}
}
pub fn state_mutability(&self) -> Option<&StateMutability> {
match self {
Self::Function(definition) => definition.state_mutability.as_ref(),
Self::Modifier(_) => None,
}
}
}
impl Function {
pub fn new_function(contract: Option<ContractRef>, definition: FunctionDefinition) -> Self {
Self {
ufid: UFID::next(),
contract,
definition: FunctionVariant::Function(definition),
steps: vec![],
}
}
pub fn new_modifier(contract: ContractRef, definition: ModifierDefinition) -> Self {
Self {
ufid: UFID::next(),
contract: Some(contract),
definition: FunctionVariant::Modifier(definition),
steps: vec![],
}
}
}