use crate::dag_id::DagId;
use crate::syntax::dimension::Dimension;
use crate::syntax::names::{NameDef, NameNamespace, ResolvedName, namespace};
use crate::registry::time_scale::TimeScale;
use crate::registry::types::{DimensionRegistry, NatRangeIndex, NatRangeIndexError};
use crate::syntax::nat::NatPolyForm;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TypeNameRef<Ns: NameNamespace> {
name: NameDef<Ns>,
resolved: ResolvedName<Ns>,
}
impl<Ns: NameNamespace> TypeNameRef<Ns> {
#[must_use]
pub fn from_resolved(resolved: ResolvedName<Ns>) -> Self {
Self {
name: resolved.to_unowned_def_name(),
resolved,
}
}
#[must_use]
pub const fn with_display_leaf(name: NameDef<Ns>, resolved: ResolvedName<Ns>) -> Self {
Self { name, resolved }
}
#[must_use]
pub fn with_owner(owner: DagId, name: NameDef<Ns>) -> Self {
Self::from_resolved(ResolvedName::from_def(owner, name))
}
#[must_use]
pub const fn name(&self) -> &NameDef<Ns> {
&self.name
}
#[must_use]
pub const fn resolved(&self) -> &ResolvedName<Ns> {
&self.resolved
}
#[must_use]
pub fn matches_ref(&self, other: &Self) -> bool {
self.resolved() == other.resolved()
}
#[must_use]
pub fn as_str(&self) -> &str {
self.name.as_str()
}
#[must_use]
pub fn to_unowned_name(&self) -> NameDef<Ns> {
self.name.clone()
}
}
impl<Ns: NameNamespace> From<ResolvedName<Ns>> for TypeNameRef<Ns> {
fn from(resolved: ResolvedName<Ns>) -> Self {
Self::from_resolved(resolved)
}
}
impl<Ns: NameNamespace> std::fmt::Display for TypeNameRef<Ns> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.name.fmt(f)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum NatRangeIndexRef {
Concrete(NatRangeIndex),
Symbolic(NatPolyForm),
}
impl NatRangeIndexRef {
pub fn from_form(form: NatPolyForm) -> Result<Self, NatRangeIndexError> {
if form.is_constant() {
NatRangeIndex::try_from_u64(form.constant()).map(Self::Concrete)
} else {
Ok(Self::Symbolic(form))
}
}
#[must_use]
pub const fn concrete_index(&self) -> Option<NatRangeIndex> {
match self {
Self::Concrete(index) => Some(*index),
Self::Symbolic(_) => None,
}
}
#[must_use]
pub fn form(&self) -> NatPolyForm {
match self {
Self::Concrete(index) => NatPolyForm::from_constant(index.size_u64()),
Self::Symbolic(form) => form.clone(),
}
}
#[must_use]
pub fn display_name(&self) -> NameDef<namespace::Index> {
match self {
Self::Concrete(index) => index.display_name(),
Self::Symbolic(form) => NameDef::new(format!("range({})", form.format())),
}
}
#[must_use]
pub fn matches_ref(&self, other: &Self) -> bool {
match (self, other) {
(Self::Concrete(lhs), Self::Concrete(rhs)) => lhs == rhs,
(Self::Symbolic(lhs), Self::Symbolic(rhs)) => lhs == rhs,
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum IndexTypeRef {
Declared(TypeNameRef<namespace::Index>),
NatRange(NatRangeIndexRef),
}
impl IndexTypeRef {
#[must_use]
pub fn from_resolved(resolved: ResolvedName<namespace::Index>) -> Self {
Self::Declared(TypeNameRef::from_resolved(resolved))
}
#[must_use]
pub fn with_owner(owner: DagId, name: NameDef<namespace::Index>) -> Self {
Self::Declared(TypeNameRef::with_owner(owner, name))
}
#[must_use]
pub const fn with_display_leaf(
name: NameDef<namespace::Index>,
resolved: ResolvedName<namespace::Index>,
) -> Self {
Self::Declared(TypeNameRef::with_display_leaf(name, resolved))
}
#[must_use]
pub const fn from_nat_range(index: NatRangeIndex) -> Self {
Self::NatRange(NatRangeIndexRef::Concrete(index))
}
pub fn from_nat_range_form(form: NatPolyForm) -> Result<Self, NatRangeIndexError> {
NatRangeIndexRef::from_form(form).map(Self::NatRange)
}
#[must_use]
pub const fn from_nat_range_ref(reference: NatRangeIndexRef) -> Self {
Self::NatRange(reference)
}
#[must_use]
pub const fn declared_name(&self) -> Option<&NameDef<namespace::Index>> {
match self {
Self::Declared(reference) => Some(reference.name()),
Self::NatRange(_) => None,
}
}
#[must_use]
pub const fn declared_resolved(&self) -> Option<&ResolvedName<namespace::Index>> {
match self {
Self::Declared(reference) => Some(reference.resolved()),
Self::NatRange(_) => None,
}
}
#[must_use]
pub const fn nat_range_ref(&self) -> Option<&NatRangeIndexRef> {
match self {
Self::Declared(_) => None,
Self::NatRange(reference) => Some(reference),
}
}
#[must_use]
pub const fn nat_range(&self) -> Option<NatRangeIndex> {
match self {
Self::NatRange(reference) => reference.concrete_index(),
Self::Declared(_) => None,
}
}
#[must_use]
pub fn nat_range_form(&self) -> Option<NatPolyForm> {
self.nat_range_ref().map(NatRangeIndexRef::form)
}
#[must_use]
pub fn display_name(&self) -> NameDef<namespace::Index> {
match self {
Self::Declared(reference) => reference.to_unowned_name(),
Self::NatRange(reference) => reference.display_name(),
}
}
#[must_use]
pub fn matches_ref(&self, other: &Self) -> bool {
match (self, other) {
(Self::Declared(lhs), Self::Declared(rhs)) => lhs.matches_ref(rhs),
(Self::NatRange(lhs), Self::NatRange(rhs)) => lhs.matches_ref(rhs),
_ => false,
}
}
#[must_use]
pub fn to_unowned_name(&self) -> NameDef<namespace::Index> {
self.display_name()
}
}
impl From<ResolvedName<namespace::Index>> for IndexTypeRef {
fn from(resolved: ResolvedName<namespace::Index>) -> Self {
Self::from_resolved(resolved)
}
}
impl std::fmt::Display for IndexTypeRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.display_name().fmt(f)
}
}
pub type StructTypeRef = TypeNameRef<namespace::StructType>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DeclaredType {
Scalar(Dimension),
Bool,
Int,
Datetime(TimeScale),
IndexArg(IndexTypeRef),
Struct(StructTypeRef, Vec<Self>),
Indexed {
element: Box<Self>,
index: IndexTypeRef,
},
}
impl DeclaredType {
#[must_use]
pub fn format(&self, dims: &DimensionRegistry) -> String {
match self {
Self::Scalar(d) => dims.format_dimension(d),
Self::Bool => "Bool".to_string(),
Self::Int => "Int".to_string(),
Self::Datetime(scale) => {
if scale.is_utc() {
"Datetime".to_string()
} else {
format!("Datetime<{scale}>")
}
}
Self::IndexArg(index) => format!("index {index}"),
Self::Struct(name, args) => {
if args.is_empty() {
name.to_string()
} else {
let args_str: Vec<String> = args.iter().map(|a| a.format(dims)).collect();
format!("{name}<{}>", args_str.join(", "))
}
}
Self::Indexed { element, index } => {
format!("{}[{index}]", element.format(dims))
}
}
}
}