mago_codex/identifier/
function_like.rs

1use mago_database::file::FileId;
2use serde::Deserialize;
3use serde::Serialize;
4
5use mago_atom::Atom;
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    /// * `Atom` - The fully qualified name (FQN) of the function.
18    Function(Atom),
19    /// A method within a class, interface, trait, or enum.
20    /// * `Atom` - The fully qualified class name (FQCN) of the containing structure.
21    /// * `Atom` - The name of the method.
22    Method(Atom, Atom),
23    /// A closure (anonymous function `function() {}` or arrow function `fn() => expr`).
24    ///
25    /// * `FileId` - The identifier of the file where the closure is defined.
26    /// * `Position` - The starting position of the closure definition.
27    Closure(FileId, Position),
28}
29
30impl FunctionLikeIdentifier {
31    /// Checks if this identifier represents a `Function`.
32    #[inline]
33    pub const fn is_function(&self) -> bool {
34        matches!(self, FunctionLikeIdentifier::Function(_))
35    }
36
37    /// Checks if this identifier represents a `Method`.
38    #[inline]
39    pub const fn is_method(&self) -> bool {
40        matches!(self, FunctionLikeIdentifier::Method(_, _))
41    }
42
43    /// Checks if this identifier represents a `Closure`.
44    #[inline]
45    pub const fn is_closure(&self) -> bool {
46        matches!(self, FunctionLikeIdentifier::Closure(_, _))
47    }
48
49    /// If this identifier represents a method, returns it as a `MethodIdentifier`.
50    /// Otherwise, returns `None`.
51    #[inline]
52    pub const fn as_method_identifier(&self) -> Option<MethodIdentifier> {
53        match self {
54            FunctionLikeIdentifier::Method(fq_classlike_name, method_name) => {
55                Some(MethodIdentifier::new(*fq_classlike_name, *method_name))
56            }
57            _ => None,
58        }
59    }
60
61    /// Returns a string representation of the kind of function-like construct.
62    #[inline]
63    pub const fn title_kind_str(&self) -> &'static str {
64        match self {
65            FunctionLikeIdentifier::Function(_) => "Function",
66            FunctionLikeIdentifier::Method(_, _) => "Method",
67            FunctionLikeIdentifier::Closure(_, _) => "Closure",
68        }
69    }
70
71    /// Returns a string representation of the kind of function-like construct.
72    #[inline]
73    pub const fn kind_str(&self) -> &'static str {
74        match self {
75            FunctionLikeIdentifier::Function(_) => "function",
76            FunctionLikeIdentifier::Method(_, _) => "method",
77            FunctionLikeIdentifier::Closure(_, _) => "closure",
78        }
79    }
80
81    /// Converts the identifier to a human-readable string representation.
82    ///
83    /// For closures, this typically includes the filename and starting offset.
84    #[inline]
85    pub fn as_string(&self) -> String {
86        match self {
87            FunctionLikeIdentifier::Function(fn_name) => fn_name.to_string(),
88            FunctionLikeIdentifier::Method(fq_classlike_name, method_name) => {
89                format!("{}::{}", fq_classlike_name, method_name)
90            }
91            FunctionLikeIdentifier::Closure(file_id, position) => {
92                format!("{}:{}", file_id, position.offset)
93            }
94        }
95    }
96
97    /// Creates a stable string representation suitable for use as a key or unique ID.
98    #[inline]
99    pub fn to_hash(&self) -> String {
100        match self {
101            FunctionLikeIdentifier::Function(fn_name) => fn_name.to_string(),
102            FunctionLikeIdentifier::Method(fq_classlike_name, method_name) => {
103                format!("{fq_classlike_name}::{method_name}")
104            }
105            FunctionLikeIdentifier::Closure(file_id, position) => {
106                format!("{}::{}", file_id, position.offset)
107            }
108        }
109    }
110}