Skip to main content

swift_demangler/
metadata.rs

1//! Type metadata symbol representation.
2//!
3//! Type metadata symbols represent runtime type information used by Swift
4//! for dynamic dispatch, reflection, and generic instantiation.
5
6use crate::helpers::NodeExt;
7use crate::raw::{Node, NodeKind};
8use crate::symbol::Symbol;
9use crate::types::TypeRef;
10
11/// A Swift type metadata symbol.
12pub struct Metadata<'ctx> {
13    raw: Node<'ctx>,
14    inner: Option<Box<Symbol<'ctx>>>,
15}
16
17impl<'ctx> Metadata<'ctx> {
18    /// Create a Metadata from a raw node.
19    pub fn new(raw: Node<'ctx>) -> Self {
20        Self { raw, inner: None }
21    }
22
23    /// Create a Metadata with an inner symbol (for sibling patterns like DefaultOverride).
24    pub fn with_inner(raw: Node<'ctx>, inner: Symbol<'ctx>) -> Self {
25        Self {
26            raw,
27            inner: Some(Box::new(inner)),
28        }
29    }
30
31    /// Get the inner symbol, if any.
32    pub fn inner(&self) -> Option<&Symbol<'ctx>> {
33        self.inner.as_deref()
34    }
35
36    /// Get the underlying raw node.
37    pub fn raw(&self) -> Node<'ctx> {
38        self.raw
39    }
40
41    /// Get the kind of metadata.
42    pub fn kind(&self) -> MetadataKind {
43        match self.raw.kind() {
44            NodeKind::TypeMetadata => MetadataKind::Type,
45            NodeKind::FullTypeMetadata => MetadataKind::FullType,
46            NodeKind::TypeMetadataAccessFunction => MetadataKind::AccessFunction,
47            NodeKind::TypeMetadataCompletionFunction => MetadataKind::CompletionFunction,
48            NodeKind::TypeMetadataInstantiationFunction => MetadataKind::InstantiationFunction,
49            NodeKind::TypeMetadataInstantiationCache => MetadataKind::InstantiationCache,
50            NodeKind::TypeMetadataLazyCache => MetadataKind::LazyCache,
51            NodeKind::TypeMetadataSingletonInitializationCache => {
52                MetadataKind::SingletonInitializationCache
53            }
54            NodeKind::TypeMetadataDemanglingCache => MetadataKind::DemanglingCache,
55            NodeKind::GenericTypeMetadataPattern => MetadataKind::GenericPattern,
56            NodeKind::MetadataInstantiationCache => MetadataKind::MetadataInstantiationCache,
57            NodeKind::NoncanonicalSpecializedGenericTypeMetadata => {
58                MetadataKind::NoncanonicalSpecializedGeneric
59            }
60            NodeKind::NoncanonicalSpecializedGenericTypeMetadataCache => {
61                MetadataKind::NoncanonicalSpecializedGenericCache
62            }
63            NodeKind::CanonicalSpecializedGenericTypeMetadataAccessFunction => {
64                MetadataKind::CanonicalSpecializedGenericAccessFunction
65            }
66            NodeKind::AssociatedTypeMetadataAccessor => MetadataKind::AssociatedTypeAccessor,
67            NodeKind::DefaultAssociatedTypeMetadataAccessor => {
68                MetadataKind::DefaultAssociatedTypeAccessor
69            }
70            NodeKind::ClassMetadataBaseOffset => MetadataKind::ClassBaseOffset,
71            NodeKind::ObjCMetadataUpdateFunction => MetadataKind::ObjCUpdateFunction,
72            NodeKind::FieldOffset => MetadataKind::FieldOffset,
73            NodeKind::Metaclass => MetadataKind::Metaclass,
74            NodeKind::IVarInitializer => MetadataKind::IVarInitializer,
75            NodeKind::IVarDestroyer => MetadataKind::IVarDestroyer,
76            NodeKind::HasSymbolQuery => MetadataKind::HasSymbolQuery,
77            NodeKind::DefaultOverride => MetadataKind::DefaultOverride,
78            NodeKind::PropertyWrapperBackingInitializer => {
79                MetadataKind::PropertyWrapperBackingInitializer
80            }
81            NodeKind::MethodLookupFunction => MetadataKind::MethodLookupFunction,
82            _ => MetadataKind::Other,
83        }
84    }
85
86    /// Get the type this metadata is for.
87    pub fn metadata_type(&self) -> Option<TypeRef<'ctx>> {
88        // First try standard Type child
89        if let Some(type_ref) = self.raw.extract_type_ref() {
90            return Some(type_ref);
91        }
92        // Some metadata nodes have the type directly as a child
93        for child in self.raw.children() {
94            match child.kind() {
95                NodeKind::Class
96                | NodeKind::Structure
97                | NodeKind::Enum
98                | NodeKind::Protocol
99                | NodeKind::BoundGenericClass
100                | NodeKind::BoundGenericStructure
101                | NodeKind::BoundGenericEnum => {
102                    return Some(TypeRef::new(child));
103                }
104                _ => {}
105            }
106        }
107        None
108    }
109
110    /// Check if this is a metadata accessor (function that returns metadata).
111    pub fn is_accessor(&self) -> bool {
112        matches!(
113            self.kind(),
114            MetadataKind::AccessFunction
115                | MetadataKind::AssociatedTypeAccessor
116                | MetadataKind::DefaultAssociatedTypeAccessor
117                | MetadataKind::CanonicalSpecializedGenericAccessFunction
118        )
119    }
120
121    /// Check if this is a cache for metadata.
122    pub fn is_cache(&self) -> bool {
123        matches!(
124            self.kind(),
125            MetadataKind::InstantiationCache
126                | MetadataKind::LazyCache
127                | MetadataKind::SingletonInitializationCache
128                | MetadataKind::DemanglingCache
129                | MetadataKind::MetadataInstantiationCache
130                | MetadataKind::NoncanonicalSpecializedGenericCache
131        )
132    }
133}
134
135impl std::fmt::Debug for Metadata<'_> {
136    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137        let mut s = f.debug_struct("Metadata");
138        s.field("kind", &self.kind());
139        if let Some(meta_type) = self.metadata_type() {
140            s.field("metadata_type", &meta_type);
141        }
142        if let Some(inner) = &self.inner {
143            s.field("inner", inner);
144        }
145        s.finish()
146    }
147}
148
149impl std::fmt::Display for Metadata<'_> {
150    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151        write!(f, "{}", self.raw)
152    }
153}
154
155/// The kind of type metadata.
156#[derive(Debug, Clone, Copy, PartialEq, Eq)]
157pub enum MetadataKind {
158    /// Type metadata.
159    Type,
160    /// Full type metadata (includes value witness table pointer).
161    FullType,
162    /// Type metadata access function.
163    AccessFunction,
164    /// Type metadata completion function.
165    CompletionFunction,
166    /// Type metadata instantiation function (for generics).
167    InstantiationFunction,
168    /// Type metadata instantiation cache.
169    InstantiationCache,
170    /// Type metadata lazy cache.
171    LazyCache,
172    /// Type metadata singleton initialization cache.
173    SingletonInitializationCache,
174    /// Type metadata demangling cache.
175    DemanglingCache,
176    /// Generic type metadata pattern.
177    GenericPattern,
178    /// Metadata instantiation cache.
179    MetadataInstantiationCache,
180    /// Non-canonical specialized generic type metadata.
181    NoncanonicalSpecializedGeneric,
182    /// Non-canonical specialized generic type metadata cache.
183    NoncanonicalSpecializedGenericCache,
184    /// Canonical specialized generic type metadata access function.
185    CanonicalSpecializedGenericAccessFunction,
186    /// Associated type metadata accessor.
187    AssociatedTypeAccessor,
188    /// Default associated type metadata accessor.
189    DefaultAssociatedTypeAccessor,
190    /// Class metadata base offset.
191    ClassBaseOffset,
192    /// Objective-C metadata update function.
193    ObjCUpdateFunction,
194    /// Field offset.
195    FieldOffset,
196    /// Metaclass.
197    Metaclass,
198    /// Instance variable initializer.
199    IVarInitializer,
200    /// Instance variable destroyer.
201    IVarDestroyer,
202    /// Has symbol query (runtime availability check).
203    HasSymbolQuery,
204    /// Default override.
205    DefaultOverride,
206    /// Property wrapper backing initializer.
207    PropertyWrapperBackingInitializer,
208    /// Method lookup function (dynamic dispatch).
209    MethodLookupFunction,
210    /// Other metadata kind.
211    Other,
212}
213
214impl MetadataKind {
215    /// Get a human-readable name for this metadata kind.
216    pub fn name(&self) -> &'static str {
217        match self {
218            MetadataKind::Type => "type metadata",
219            MetadataKind::FullType => "full type metadata",
220            MetadataKind::AccessFunction => "type metadata access function",
221            MetadataKind::CompletionFunction => "type metadata completion function",
222            MetadataKind::InstantiationFunction => "type metadata instantiation function",
223            MetadataKind::InstantiationCache => "type metadata instantiation cache",
224            MetadataKind::LazyCache => "type metadata lazy cache",
225            MetadataKind::SingletonInitializationCache => {
226                "type metadata singleton initialization cache"
227            }
228            MetadataKind::DemanglingCache => "type metadata demangling cache",
229            MetadataKind::GenericPattern => "generic type metadata pattern",
230            MetadataKind::MetadataInstantiationCache => "metadata instantiation cache",
231            MetadataKind::NoncanonicalSpecializedGeneric => {
232                "non-canonical specialized generic type metadata"
233            }
234            MetadataKind::NoncanonicalSpecializedGenericCache => {
235                "non-canonical specialized generic type metadata cache"
236            }
237            MetadataKind::CanonicalSpecializedGenericAccessFunction => {
238                "canonical specialized generic type metadata access function"
239            }
240            MetadataKind::AssociatedTypeAccessor => "associated type metadata accessor",
241            MetadataKind::DefaultAssociatedTypeAccessor => {
242                "default associated type metadata accessor"
243            }
244            MetadataKind::ClassBaseOffset => "class metadata base offset",
245            MetadataKind::ObjCUpdateFunction => "Objective-C metadata update function",
246            MetadataKind::FieldOffset => "field offset",
247            MetadataKind::Metaclass => "metaclass",
248            MetadataKind::IVarInitializer => "instance variable initializer",
249            MetadataKind::IVarDestroyer => "instance variable destroyer",
250            MetadataKind::HasSymbolQuery => "has symbol query",
251            MetadataKind::DefaultOverride => "default override",
252            MetadataKind::PropertyWrapperBackingInitializer => {
253                "property wrapper backing initializer"
254            }
255            MetadataKind::MethodLookupFunction => "method lookup function",
256            MetadataKind::Other => "metadata",
257        }
258    }
259}
260
261#[cfg(test)]
262mod tests {
263    use crate::Symbol;
264    use crate::raw::Context;
265
266    #[test]
267    fn test_type_metadata() {
268        let ctx = Context::new();
269        // type metadata for Swift.UInt16
270        let symbol = Symbol::parse(&ctx, "$ss6UInt16VN").unwrap();
271        assert!(symbol.is_metadata());
272        if let Symbol::Metadata(meta) = symbol {
273            assert_eq!(meta.kind(), super::MetadataKind::Type);
274            let meta_type = meta.metadata_type().expect("should have metadata type");
275            // Module info is in the type: Swift.UInt16
276            assert!(meta_type.to_string().contains("Swift"));
277        } else {
278            panic!("Expected metadata");
279        }
280    }
281
282    #[test]
283    fn test_type_metadata_access_function() {
284        let ctx = Context::new();
285        // type metadata accessor for Swift.Int
286        let symbol = Symbol::parse(&ctx, "$sSiMa").unwrap();
287        assert!(symbol.is_metadata());
288        if let Symbol::Metadata(meta) = symbol {
289            assert_eq!(meta.kind(), super::MetadataKind::AccessFunction);
290            assert!(meta.is_accessor());
291            let meta_type = meta.metadata_type().expect("should have metadata type");
292            // Module info is in the type: Swift.Int
293            assert!(meta_type.to_string().contains("Swift"));
294        } else {
295            panic!("Expected metadata");
296        }
297    }
298}