mago_codex/identifier/
function_like.rs

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