use smol_str::SmolStr;
#[cfg(test)]
use {
    crate::proptest::{any_nonempty_smolstr, any_nonempty_string},
    ::proptest_derive::Arbitrary,
};
use crate::types::{EdgeKind, PolyFuncType, Signature};
use crate::types::{Type, TypeBound};
use super::dataflow::DataflowParent;
use super::StaticTag;
use super::{impl_op_name, OpTag, OpTrait};
#[derive(Debug, Clone, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
#[cfg_attr(test, derive(Arbitrary))]
pub struct Module {
    }
impl Module {
    pub const fn new() -> Self {
        Self {}
    }
}
impl_op_name!(Module);
impl StaticTag for Module {
    const TAG: OpTag = OpTag::ModuleRoot;
}
impl OpTrait for Module {
    fn description(&self) -> &str {
        "The root of a module, parent of all other `OpType`s"
    }
    fn tag(&self) -> super::OpTag {
        <Self as StaticTag>::TAG
    }
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[cfg_attr(test, derive(Arbitrary))]
pub struct FuncDefn {
    #[cfg_attr(test, proptest(strategy = "any_nonempty_string()"))]
    pub name: String,
    pub signature: PolyFuncType,
}
impl_op_name!(FuncDefn);
impl StaticTag for FuncDefn {
    const TAG: OpTag = OpTag::FuncDefn;
}
impl DataflowParent for FuncDefn {
    fn inner_signature(&self) -> Signature {
        self.signature.body().clone()
    }
}
impl OpTrait for FuncDefn {
    fn description(&self) -> &str {
        "A function definition"
    }
    fn tag(&self) -> OpTag {
        <Self as StaticTag>::TAG
    }
    fn static_output(&self) -> Option<EdgeKind> {
        Some(EdgeKind::Function(self.signature.clone()))
    }
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[cfg_attr(test, derive(Arbitrary))]
pub struct FuncDecl {
    #[cfg_attr(test, proptest(strategy = "any_nonempty_string()"))]
    pub name: String,
    pub signature: PolyFuncType,
}
impl_op_name!(FuncDecl);
impl StaticTag for FuncDecl {
    const TAG: OpTag = OpTag::Function;
}
impl OpTrait for FuncDecl {
    fn description(&self) -> &str {
        "External function declaration, linked at runtime"
    }
    fn tag(&self) -> OpTag {
        <Self as StaticTag>::TAG
    }
    fn static_output(&self) -> Option<EdgeKind> {
        Some(EdgeKind::Function(self.signature.clone()))
    }
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[cfg_attr(test, derive(Arbitrary))]
pub struct AliasDefn {
    #[cfg_attr(test, proptest(strategy = "any_nonempty_smolstr()"))]
    pub name: SmolStr,
    pub definition: Type,
}
impl_op_name!(AliasDefn);
impl StaticTag for AliasDefn {
    const TAG: OpTag = OpTag::Alias;
}
impl OpTrait for AliasDefn {
    fn description(&self) -> &str {
        "A type alias definition"
    }
    fn tag(&self) -> OpTag {
        <Self as StaticTag>::TAG
    }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
pub struct AliasDecl {
    #[cfg_attr(test, proptest(strategy = "any_nonempty_smolstr()"))]
    pub name: SmolStr,
    pub bound: TypeBound,
}
impl AliasDecl {
    pub fn new(name: impl Into<SmolStr>, bound: TypeBound) -> Self {
        Self {
            name: name.into(),
            bound,
        }
    }
    pub fn name(&self) -> &str {
        self.name.as_ref()
    }
}
impl_op_name!(AliasDecl);
impl StaticTag for AliasDecl {
    const TAG: OpTag = OpTag::Alias;
}
impl OpTrait for AliasDecl {
    fn description(&self) -> &str {
        "A type alias declaration"
    }
    fn tag(&self) -> OpTag {
        <Self as StaticTag>::TAG
    }
}