Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions ext/rubydex/graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@ static const char *extract_self_receiver(VALUE opts) {
return StringValueCStr(kwarg_val);
}

// Free function for the custom Graph allocator. We always have to call into Rust to free data allocated by it
// Free function for the custom Graph allocator.
static void graph_free(void *ptr) {
if (ptr) {
rdx_graph_free(ptr);
// let the Rust side drop the Graph struct internally.
rdx_graph_drop(ptr);

// Free the TypeData Ruby object itself
xfree(ptr);
}
}

Expand All @@ -58,11 +62,18 @@ const rb_data_type_t graph_type = {
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
};

// Custom allocator for the Graph class. Calls into Rust to create a new `Arc<Mutex<Graph>>` that gets stored internally
// as a void pointer
// Custom allocator for the Graph class.
// Requests enough memory from the Ruby GC to fit a `Graph` Rust struct, then initializes it in-place.
// Only the `Graph` Rust struct itself is in the Ruby heap. Everything else it points to (e.g. all its hash maps' storage)
// are still normal Rust allocations from the Rust allocator, unknown to the Ruby GC.
static VALUE rdxr_graph_alloc(VALUE klass) {
void *graph = rdx_graph_new();
return TypedData_Wrap_Struct(klass, &graph_type, graph);
void *graph;
// Can't use `TypedData_Make_Struct`, because the Graph is a Rust type that isn't exposed directly to C.
VALUE graph_obj = rb_data_typed_object_make(klass, &graph_type, &graph, RDX_GRAPH_SIZE);

rdx_graph_init(graph);

return graph_obj;
}

// Graph#index_all: (Array[String] file_paths) -> Array[String]
Expand Down
5 changes: 3 additions & 2 deletions ext/rubydex/handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@ static const rb_data_type_t handle_type = {
};

static VALUE rdxr_handle_alloc(VALUE klass) {
HandleData *data = ALLOC(HandleData);
HandleData *data;
VALUE handle_obj = TypedData_Make_Struct(klass, HandleData, &handle_type, data);

*data = (HandleData) {
.graph_obj = Qnil,
.id = 0,
};

return TypedData_Wrap_Struct(klass, &handle_type, data);
return handle_obj;
}

static VALUE rdxr_handle_initialize(VALUE self, VALUE graph_obj, VALUE id_val) {
Expand Down
6 changes: 3 additions & 3 deletions rust/rubydex-sys/src/declaration_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ pub unsafe extern "C" fn rdx_declaration_unqualified_name(pointer: GraphPointer,
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - The returned pointer must be freed with `rdx_declaration_definitions_iter_free`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_declaration_definitions_iter_new(
Expand Down Expand Up @@ -452,7 +452,7 @@ pub unsafe extern "C" fn rdx_constant_alias_target(pointer: GraphPointer, decl_i
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - The returned pointer must be freed with `rdx_constant_references_iter_free`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_declaration_constant_references_iter_new(
Expand Down Expand Up @@ -485,7 +485,7 @@ pub unsafe extern "C" fn rdx_declaration_constant_references_iter_new(
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - The returned pointer must be freed with `rdx_method_references_iter_free`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_declaration_method_references_iter_new(
Expand Down
16 changes: 8 additions & 8 deletions rust/rubydex-sys/src/definition_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ pub struct CommentArray {
/// Caller must free the returned pointer with `rdx_definition_comments_free` and each inner string with `free_c_string` if needed.
///
/// # Safety
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `definition_id` must be a valid definition id.
///
/// # Panics
Expand Down Expand Up @@ -232,7 +232,7 @@ pub unsafe extern "C" fn rdx_definition_comments_free(ptr: *mut CommentArray) {
/// Caller must free the returned pointer with `rdx_location_free`.
///
/// # Safety
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `definition_id` must be a valid definition id.
///
/// # Panics
Expand All @@ -256,7 +256,7 @@ pub unsafe extern "C" fn rdx_definition_location(pointer: GraphPointer, definiti
/// with `free_c_declaration`.
///
/// # Safety
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `definition_id` must be a valid definition id.
///
/// # Panics
Expand All @@ -280,7 +280,7 @@ pub unsafe extern "C" fn rdx_definition_declaration(pointer: GraphPointer, defin
/// Caller must free the returned pointer with `free_u64`.
///
/// # Safety
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `definition_id` must be a valid definition id.
///
/// # Panics
Expand Down Expand Up @@ -331,7 +331,7 @@ where
/// Returns true if the definition is deprecated.
///
/// # Safety
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `definition_id` must be a valid definition id.
///
/// # Panics
Expand All @@ -352,7 +352,7 @@ pub unsafe extern "C" fn rdx_definition_is_deprecated(pointer: GraphPointer, def
/// Caller must free the returned pointer with `rdx_location_free`.
///
/// # Safety
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `definition_id` must be a valid definition id.
///
/// # Panics
Expand All @@ -376,7 +376,7 @@ pub unsafe extern "C" fn rdx_definition_name_location(pointer: GraphPointer, def
/// must free with `free_c_constant_reference`.
///
/// # Safety
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `definition_id` must be a valid definition id for a class definition.
///
/// # Panics
Expand Down Expand Up @@ -462,7 +462,7 @@ fn map_mixin_kind(mixin: &Mixin) -> MixinKind {
/// Returns NULL for definition types that do not support mixins.
///
/// # Safety
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `definition_id` must be a valid definition id.
///
/// # Panics
Expand Down
2 changes: 1 addition & 1 deletion rust/rubydex-sys/src/diagnostic_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl DiagnosticArray {
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - The pointed graph must remain alive for the duration of the call.
///
/// # Panics
Expand Down
2 changes: 1 addition & 1 deletion rust/rubydex-sys/src/document_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub unsafe extern "C" fn rdx_document_uri(pointer: GraphPointer, uri_id: u64) ->
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - The returned pointer must be freed with `rdx_document_definitions_iter_free`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_document_definitions_iter_new(pointer: GraphPointer, uri_id: u64) -> *mut DefinitionsIter {
Expand Down
75 changes: 46 additions & 29 deletions rust/rubydex-sys/src/graph_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,38 +23,55 @@ use std::{mem, ptr};

pub type GraphPointer = *mut c_void;

/// Creates a new graph within a mutex. This is meant to be used when creating new Graph objects in Ruby
/// Returns the number of bytes needed to store a Graph in externally allocated memory.
#[unsafe(no_mangle)]
pub extern "C" fn rdx_graph_new() -> GraphPointer {
Box::into_raw(Box::new(Graph::new())) as GraphPointer
pub static RDX_GRAPH_SIZE: usize = mem::size_of::<Graph>();

/// Initializes a Graph in-place at the given `pointer`.
///
/// # Safety
///
/// `pointer` must point to valid, properly aligned memory of at least `RDX_GRAPH_SIZE` bytes.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_graph_init(pointer: GraphPointer) {
// Ruby's allocator only guarantees 16 byte alignment on the 64-bit platforms we support.
// Let's make sure we don't have higher alignment requirements (e.g. if we add a u128 in the future).
const _: () = assert!(
mem::align_of::<Graph>() <= 16,
"Graph alignment exceeds the 16-byte alignment guaranteed by Ruby's allocator"
);

unsafe {
pointer.cast::<Graph>().write(Graph::new());
}
}

/// Frees a Graph through its pointer
/// Drops a Graph initialized by `rdx_graph_init` without freeing the underlying memory.
///
/// # Safety
///
/// `pointer` must point to a valid initialized Graph.
#[unsafe(no_mangle)]
pub extern "C" fn rdx_graph_free(pointer: GraphPointer) {
pub unsafe extern "C" fn rdx_graph_drop(pointer: GraphPointer) {
unsafe {
let _ = Box::from_raw(pointer.cast::<Graph>());
ptr::drop_in_place(pointer.cast::<Graph>());
}
}

pub fn with_graph<F, T>(pointer: GraphPointer, action: F) -> T
where
F: FnOnce(&Graph) -> T,
{
let mut graph = unsafe { Box::from_raw(pointer.cast::<Graph>()) };
let result = action(&mut graph);
mem::forget(graph);
result
let graph = unsafe { &*pointer.cast::<Graph>() };
action(graph)
}

fn with_mut_graph<F, T>(pointer: GraphPointer, action: F) -> T
where
F: FnOnce(&mut Graph) -> T,
{
let mut graph = unsafe { Box::from_raw(pointer.cast::<Graph>()) };
let result = action(&mut graph);
mem::forget(graph);
result
let graph = unsafe { &mut *pointer.cast::<Graph>() };
action(graph)
}

/// Searches the graph using exact substring matching
Expand Down Expand Up @@ -165,7 +182,7 @@ pub unsafe extern "C" fn rdx_graph_resolve_constant(
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `paths` must be an array of `count` valid, null-terminated UTF-8 strings.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_graph_exclude_paths(pointer: GraphPointer, paths: *const *const c_char, count: usize) {
Expand All @@ -179,7 +196,7 @@ pub unsafe extern "C" fn rdx_graph_exclude_paths(pointer: GraphPointer, paths: *
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `out_count` must be a valid, writable pointer.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_graph_excluded_paths(
Expand Down Expand Up @@ -318,7 +335,7 @@ pub extern "C" fn rdx_graph_resolve(pointer: GraphPointer) {
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `out_error_count` must be a valid, writable pointer.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_check_integrity(
Expand Down Expand Up @@ -378,7 +395,7 @@ pub unsafe extern "C" fn rdx_graph_set_encoding(pointer: GraphPointer, encoding_
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - The returned pointer must be freed with `rdx_graph_declarations_iter_free`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_graph_declarations_iter_new(pointer: GraphPointer) -> *mut DeclarationsIter {
Expand All @@ -399,7 +416,7 @@ pub unsafe extern "C" fn rdx_graph_declarations_iter_new(pointer: GraphPointer)
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - The returned pointer must be freed with `rdx_graph_documents_iter_free`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_graph_documents_iter_new(pointer: GraphPointer) -> *mut DocumentsIter {
Expand Down Expand Up @@ -441,7 +458,7 @@ pub unsafe extern "C" fn rdx_graph_get_declaration(pointer: GraphPointer, name:
/// Creates a new iterator over constant references by snapshotting the current set of IDs.
///
/// # Safety
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_graph_constant_references_iter_new(pointer: GraphPointer) -> *mut ConstantReferencesIter {
with_graph(pointer, |graph| {
Expand Down Expand Up @@ -472,7 +489,7 @@ pub unsafe extern "C" fn rdx_graph_constant_references_iter_new(pointer: GraphPo
/// Creates a new iterator over method references by snapshotting the current set of IDs.
///
/// # Safety
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_graph_method_references_iter_new(pointer: GraphPointer) -> *mut MethodReferencesIter {
with_graph(pointer, |graph| {
Expand All @@ -491,7 +508,7 @@ pub unsafe extern "C" fn rdx_graph_method_references_iter_new(pointer: GraphPoin
/// Caller must free with the returned pointer.
///
/// # Safety
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `require_path` must be a valid, null-terminated UTF-8 string.
/// - `load_paths` must be an array of `load_paths_count` valid, null-terminated UTF-8 strings.
#[unsafe(no_mangle)]
Expand Down Expand Up @@ -521,7 +538,7 @@ pub unsafe extern "C" fn rdx_resolve_require_path(
/// Caller must free with `free_c_string_array`.
///
/// # Safety
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `load_path` must be an array of `load_path_count` valid, null-terminated UTF-8 strings.
/// - `out_count` must be a valid, writable pointer.
#[unsafe(no_mangle)]
Expand Down Expand Up @@ -568,7 +585,7 @@ pub enum IndexSourceResult {
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `uri` must be a valid, null-terminated UTF-8 string.
/// - `language_id` must be either null or a valid, null-terminated UTF-8 string.
/// - `source` must point to a valid UTF-8 byte buffer of at least `source_len` bytes.
Expand Down Expand Up @@ -799,7 +816,7 @@ fn run_and_finalize_completion(
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `nesting` must point to `nesting_count` valid, null-terminated UTF-8 strings.
/// - `self_receiver` must be null or a valid, null-terminated UTF-8 string. When non-null, it
/// overrides the self-type (e.g., `"Foo::<Foo>"` for completion inside `def Foo.bar`), while
Expand Down Expand Up @@ -836,7 +853,7 @@ pub unsafe extern "C" fn rdx_graph_complete_expression(
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `name` must be a valid, null-terminated UTF-8 string (FQN of the namespace).
/// - `self_receiver` must be null or a valid, null-terminated UTF-8 string. When non-null, it
/// is the caller's runtime self type (e.g., for filtering `private_class_method` visibility).
Expand Down Expand Up @@ -870,7 +887,7 @@ pub unsafe extern "C" fn rdx_graph_complete_namespace_access(
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `name` must be a valid, null-terminated UTF-8 string (FQN of the receiver).
/// - `self_receiver` must be null or a valid, null-terminated UTF-8 string. When non-null, it
/// is the caller's runtime self type, used for MRI-style visibility checks.
Expand Down Expand Up @@ -904,7 +921,7 @@ pub unsafe extern "C" fn rdx_graph_complete_method_call(
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `name` must be a valid, null-terminated UTF-8 string (FQN of the method).
/// - `nesting` must point to `nesting_count` valid, null-terminated UTF-8 strings.
/// - `self_receiver` must be null or a valid, null-terminated UTF-8 string. See
Expand Down Expand Up @@ -1001,7 +1018,7 @@ pub enum CVisibility {
///
/// # Safety
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_graph_visibility(pointer: GraphPointer, declaration_id: u64) -> *const CVisibility {
with_graph(pointer, |graph| {
Expand Down
4 changes: 2 additions & 2 deletions rust/rubydex-sys/src/reference_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ pub unsafe extern "C" fn rdx_method_reference_name(pointer: GraphPointer, refere
///
/// # Safety
///
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `reference_id` must be a valid reference id.
///
/// # Panics
Expand Down Expand Up @@ -268,7 +268,7 @@ pub unsafe extern "C" fn rdx_method_reference_receiver_declaration(
///
/// # Safety
///
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
/// - `pointer` must be a valid pointer previously initialized by `rdx_graph_init`.
/// - `reference_id` must be a valid reference id.
///
/// # Panics
Expand Down
Loading
Loading