1use crate::helpers::NodeExt;
7use crate::raw::{Node, NodeKind};
8use crate::symbol::Symbol;
9use crate::types::TypeRef;
10
11pub struct Metadata<'ctx> {
13 raw: Node<'ctx>,
14 inner: Option<Box<Symbol<'ctx>>>,
15}
16
17impl<'ctx> Metadata<'ctx> {
18 pub fn new(raw: Node<'ctx>) -> Self {
20 Self { raw, inner: None }
21 }
22
23 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 pub fn inner(&self) -> Option<&Symbol<'ctx>> {
33 self.inner.as_deref()
34 }
35
36 pub fn raw(&self) -> Node<'ctx> {
38 self.raw
39 }
40
41 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 pub fn metadata_type(&self) -> Option<TypeRef<'ctx>> {
88 if let Some(type_ref) = self.raw.extract_type_ref() {
90 return Some(type_ref);
91 }
92 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 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 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
157pub enum MetadataKind {
158 Type,
160 FullType,
162 AccessFunction,
164 CompletionFunction,
166 InstantiationFunction,
168 InstantiationCache,
170 LazyCache,
172 SingletonInitializationCache,
174 DemanglingCache,
176 GenericPattern,
178 MetadataInstantiationCache,
180 NoncanonicalSpecializedGeneric,
182 NoncanonicalSpecializedGenericCache,
184 CanonicalSpecializedGenericAccessFunction,
186 AssociatedTypeAccessor,
188 DefaultAssociatedTypeAccessor,
190 ClassBaseOffset,
192 ObjCUpdateFunction,
194 FieldOffset,
196 Metaclass,
198 IVarInitializer,
200 IVarDestroyer,
202 HasSymbolQuery,
204 DefaultOverride,
206 PropertyWrapperBackingInitializer,
208 MethodLookupFunction,
210 Other,
212}
213
214impl MetadataKind {
215 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 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 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 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 assert!(meta_type.to_string().contains("Swift"));
294 } else {
295 panic!("Expected metadata");
296 }
297 }
298}