mago_codex/identifier/
function_like.rs

1use serde::Deserialize;
2use serde::Serialize;
3
4use mago_interner::StringIdentifier;
5use mago_interner::ThreadedInterner;
6use mago_span::Position;
7
8use crate::identifier::method::MethodIdentifier;
9
10/// Identifies a specific function-like construct within the codebase.
11///
12/// This distinguishes between globally/namespaced defined functions, methods within
13/// class-like structures, and closures identified by their source position.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
15pub enum FunctionLikeIdentifier {
16    /// A globally or namespaced defined function.
17    /// * `StringIdentifier` - The fully qualified name (FQN) of the function.
18    Function(StringIdentifier),
19    /// A method within a class, interface, trait, or enum.
20    /// * `StringIdentifier` - The fully qualified class name (FQCN) of the containing structure.
21    /// * `StringIdentifier` - The name of the method.
22    Method(StringIdentifier, StringIdentifier),
23    /// A closure (anonymous function `function() {}` or arrow function `fn() => expr`).
24    /// * `Position` - The starting position (source file and offset) of the closure definition.
25    Closure(Position),
26}
27
28impl FunctionLikeIdentifier {
29    /// Checks if this identifier represents a `Function`.
30    #[inline]
31    pub const fn is_function(&self) -> bool {
32        matches!(self, FunctionLikeIdentifier::Function(_))
33    }
34
35    /// Checks if this identifier represents a `Method`.
36    #[inline]
37    pub const fn is_method(&self) -> bool {
38        matches!(self, FunctionLikeIdentifier::Method(_, _))
39    }
40
41    /// Checks if this identifier represents a `Closure`.
42    #[inline]
43    pub const fn is_closure(&self) -> bool {
44        matches!(self, FunctionLikeIdentifier::Closure(_))
45    }
46
47    /// If this identifier represents a method, returns it as a `MethodIdentifier`.
48    /// Otherwise, returns `None`.
49    #[inline]
50    pub const fn as_method_identifier(&self) -> Option<MethodIdentifier> {
51        match self {
52            FunctionLikeIdentifier::Method(fq_classlike_name, method_name) => {
53                Some(MethodIdentifier::new(*fq_classlike_name, *method_name))
54            }
55            _ => None,
56        }
57    }
58
59    /// Returns a string representation of the kind of function-like construct.
60    #[inline]
61    pub const fn title_kind_str(&self) -> &'static str {
62        match self {
63            FunctionLikeIdentifier::Function(_) => "Function",
64            FunctionLikeIdentifier::Method(_, _) => "Method",
65            FunctionLikeIdentifier::Closure(_) => "Closure",
66        }
67    }
68
69    /// Returns a string representation of the kind of function-like construct.
70    #[inline]
71    pub const fn kind_str(&self) -> &'static str {
72        match self {
73            FunctionLikeIdentifier::Function(_) => "function",
74            FunctionLikeIdentifier::Method(_, _) => "method",
75            FunctionLikeIdentifier::Closure(_) => "closure",
76        }
77    }
78
79    /// Converts the identifier to a human-readable string representation using the provided interner.
80    ///
81    /// For closures, this typically includes the filename and starting offset.
82    ///
83    /// # Arguments
84    ///
85    /// * `interner` - A reference to the `ThreadedInterner` used to resolve `StringIdentifier`s.
86    #[inline]
87    pub fn as_string(&self, interner: &ThreadedInterner) -> String {
88        match self {
89            FunctionLikeIdentifier::Function(fn_name) => interner.lookup(fn_name).to_string(),
90            FunctionLikeIdentifier::Method(fq_classlike_name, method_name) => {
91                format!("{}::{}", interner.lookup(fq_classlike_name), interner.lookup(method_name))
92            }
93            FunctionLikeIdentifier::Closure(position) => {
94                format!("{}:{}", interner.lookup(&position.source.value()), position.offset)
95            }
96        }
97    }
98
99    /// Creates a stable string representation suitable for use as a key or unique ID,
100    /// without requiring an interner lookup.
101    ///
102    /// This uses the internal representation of `StringIdentifier`
103    /// and position information directly.
104    #[inline]
105    pub fn to_hash(&self) -> String {
106        match self {
107            FunctionLikeIdentifier::Function(fn_name) => fn_name.to_string(),
108            FunctionLikeIdentifier::Method(fq_classlike_name, method_name) => {
109                format!("{fq_classlike_name}::{method_name}")
110            }
111            FunctionLikeIdentifier::Closure(position) => {
112                format!("{}::{}", position.source.value(), position.offset)
113            }
114        }
115    }
116}