-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathreference_api.rs
More file actions
304 lines (272 loc) · 10.1 KB
/
reference_api.rs
File metadata and controls
304 lines (272 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
//! C API for exposing references through ID handles (like definitions)
use std::ffi::CString;
use std::ptr;
use crate::declaration_api::CDeclaration;
use crate::graph_api::{GraphPointer, with_graph};
use crate::location_api::{Location, create_location_for_uri_and_offset};
use libc::c_char;
use rubydex::model::graph::Graph;
use rubydex::model::ids::{ConstantReferenceId, MethodReferenceId};
use rubydex::model::name::NameRef;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct CConstantReference {
pub id: u64,
pub declaration_id: u64,
}
impl CConstantReference {
/// Build a `CConstantReference` from a graph and reference ID. Sets `declaration_id` to 0 when the reference is
/// unresolved.
///
/// # Panics
///
/// This function will panic if there's inconsistent data in the graph
#[must_use]
pub fn from_id(graph: &Graph, ref_id: ConstantReferenceId) -> Self {
let reference = graph
.constant_references()
.get(&ref_id)
.expect("Constant reference not found");
let name_ref = graph.names().get(reference.name_id()).expect("Name ID should exist");
let declaration_id = match name_ref {
NameRef::Resolved(resolved) => **resolved.declaration_id(),
NameRef::Unresolved(_) => 0,
};
Self {
id: *ref_id,
declaration_id,
}
}
}
#[derive(Debug)]
pub struct ConstantReferencesIter {
entries: Box<[CConstantReference]>,
index: usize,
}
iterator!(ConstantReferencesIter, entries: CConstantReference);
/// # Safety
/// `iter` must be a valid pointer previously returned by `ConstantReferencesIter::new`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_constant_references_iter_len(iter: *const ConstantReferencesIter) -> usize {
unsafe { ConstantReferencesIter::len(iter) }
}
/// # Safety
/// - `iter` must be a valid pointer previously returned by `ConstantReferencesIter::new`.
/// - `out` must be a valid, writable pointer.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_constant_references_iter_next(
iter: *mut ConstantReferencesIter,
out: *mut CConstantReference,
) -> bool {
unsafe { ConstantReferencesIter::next(iter, out) }
}
/// # Safety
/// - `iter` must be a pointer previously returned by `ConstantReferencesIter::new`.
/// - `iter` must not be used after being freed.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_constant_references_iter_free(iter: *mut ConstantReferencesIter) {
unsafe { ConstantReferencesIter::free(iter) }
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct CMethodReference {
pub id: u64,
}
#[derive(Debug)]
pub struct MethodReferencesIter {
entries: Box<[CMethodReference]>,
index: usize,
}
iterator!(MethodReferencesIter, entries: CMethodReference);
/// # Safety
/// `iter` must be a valid pointer previously returned by `MethodReferencesIter::new`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_method_references_iter_len(iter: *const MethodReferencesIter) -> usize {
unsafe { MethodReferencesIter::len(iter) }
}
/// # Safety
/// - `iter` must be a valid pointer previously returned by `MethodReferencesIter::new`.
/// - `out` must be a valid, writable pointer.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_method_references_iter_next(
iter: *mut MethodReferencesIter,
out: *mut CMethodReference,
) -> bool {
unsafe { MethodReferencesIter::next(iter, out) }
}
/// # Safety
/// - `iter` must be a pointer previously returned by `MethodReferencesIter::new`.
/// - `iter` must not be used after being freed.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_method_references_iter_free(iter: *mut MethodReferencesIter) {
unsafe { MethodReferencesIter::free(iter) }
}
/// Returns the UTF-8 name string for a constant reference id.
/// Caller must free with `free_c_string`.
///
/// # Safety
///
/// Assumes pointer is valid.
///
/// # Panics
///
/// This function will panic if the reference cannot be found.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_constant_reference_name(pointer: GraphPointer, reference_id: u64) -> *const c_char {
with_graph(pointer, |graph| {
let ref_id = ConstantReferenceId::new(reference_id);
let reference = graph.constant_references().get(&ref_id).expect("Reference not found");
let name = graph.names().get(reference.name_id()).expect("Name ID should exist");
let name_string = graph
.strings()
.get(name.str())
.expect("String ID should exist")
.to_string();
CString::new(name_string).unwrap().into_raw().cast_const()
})
}
/// Returns the UTF-8 name string for a method reference id.
/// Caller must free with `free_c_string`.
///
/// # Safety
///
/// Assumes pointer is valid.
///
/// # Panics
///
/// This function will panic if the reference cannot be found.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_method_reference_name(pointer: GraphPointer, reference_id: u64) -> *const c_char {
with_graph(pointer, |graph| {
let ref_id = MethodReferenceId::new(reference_id);
let reference = graph.method_references().get(&ref_id).expect("Reference not found");
let name = graph
.strings()
.get(reference.str())
.expect("Name ID should exist")
.to_string();
CString::new(name).unwrap().into_raw().cast_const()
})
}
/// Returns a newly allocated `Location` for the given constant reference id.
/// Caller must free the returned pointer with `rdx_location_free`.
///
/// # Safety
///
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
/// - `reference_id` must be a valid reference id.
///
/// # Panics
///
/// This function will panic if a reference or document cannot be found.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_constant_reference_location(pointer: GraphPointer, reference_id: u64) -> *mut Location {
with_graph(pointer, |graph| {
let ref_id = ConstantReferenceId::new(reference_id);
let reference = graph.constant_references().get(&ref_id).expect("Reference not found");
let document = graph
.documents()
.get(&reference.uri_id())
.expect("Document should exist");
create_location_for_uri_and_offset(graph, document, reference.offset())
})
}
/// Returns the declaration that the given resolved constant reference points to. Returns NULL if the reference is
/// unresolved. Caller must free with `free_c_declaration`.
///
/// # Safety
///
/// Assumes pointer is valid.
///
/// # Panics
///
/// This function will panic if the reference cannot be found.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_resolved_constant_reference_declaration(
pointer: GraphPointer,
reference_id: u64,
) -> *const CDeclaration {
with_graph(pointer, |graph| {
let ref_id = ConstantReferenceId::new(reference_id);
let reference = graph.constant_references().get(&ref_id).expect("Reference not found");
let name_ref = graph.names().get(reference.name_id()).expect("Name ID should exist");
match name_ref {
NameRef::Resolved(resolved) => {
let decl_id = *resolved.declaration_id();
let decl = graph.declarations().get(&decl_id).expect("Declaration not found");
Box::into_raw(Box::new(CDeclaration::from_declaration(decl_id, decl))).cast_const()
}
NameRef::Unresolved(_) => ptr::null(),
}
})
}
/// Returns the declaration of the resolved receiver for the given method reference. Returns NULL when the method
/// reference has no tracked receiver or when the receiver could not be resolved. Caller must free with
/// `free_c_declaration`.
///
/// # Safety
///
/// Assumes pointer is valid.
///
/// # Panics
///
/// This function will panic if the reference cannot be found.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_method_reference_receiver_declaration(
pointer: GraphPointer,
reference_id: u64,
) -> *const CDeclaration {
with_graph(pointer, |graph| {
let ref_id = MethodReferenceId::new(reference_id);
let reference = graph.method_references().get(&ref_id).expect("Reference not found");
let Some(name_id) = reference.receiver() else {
return ptr::null();
};
let name_ref = graph.names().get(&name_id).expect("Name ID should exist");
match name_ref {
NameRef::Resolved(resolved) => {
let decl_id = *resolved.declaration_id();
let decl = graph.declarations().get(&decl_id).expect("Declaration not found");
Box::into_raw(Box::new(CDeclaration::from_declaration(decl_id, decl))).cast_const()
}
NameRef::Unresolved(_) => ptr::null(),
}
})
}
/// Returns a newly allocated `Location` for the given method reference id.
/// Caller must free the returned pointer with `rdx_location_free`.
///
/// # Safety
///
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
/// - `reference_id` must be a valid reference id.
///
/// # Panics
///
/// This function will panic if a reference or document cannot be found.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_method_reference_location(pointer: GraphPointer, reference_id: u64) -> *mut Location {
with_graph(pointer, |graph| {
let ref_id = MethodReferenceId::new(reference_id);
let reference = graph.method_references().get(&ref_id).expect("Reference not found");
let document = graph
.documents()
.get(&reference.uri_id())
.expect("Document should exist");
create_location_for_uri_and_offset(graph, document, reference.offset())
})
}
/// Frees a `CConstantReference` previously returned by an FFI function.
///
/// # Safety
/// - `ptr` must be a valid pointer previously returned by an FFI function that allocates a `CConstantReference`, or
/// NULL.
/// - `ptr` must not be used after being freed.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn free_c_constant_reference(ptr: *const CConstantReference) {
if !ptr.is_null() {
unsafe {
let _ = Box::from_raw(ptr.cast_mut());
}
}
}