@@ -715,60 +715,104 @@ unsafe fn completion_nesting_name_id(
715715 Ok ( name_api:: nesting_stack_to_name_id ( graph, & self_name, nesting) )
716716}
717717
718- /// Runs completion for the given receiver and returns a structured array of candidates
718+ /// The result of a completion operation, carrying either a candidate array or an error message.
719+ #[ repr( C ) ]
720+ pub struct CompletionResult {
721+ /// Non-null on success; null on error.
722+ pub candidates : * mut CompletionCandidateArray ,
723+ /// Non-null on error; null on success. Caller must free with `free_c_string`.
724+ pub error : * const c_char ,
725+ }
726+
727+ impl CompletionResult {
728+ fn success ( candidates : * mut CompletionCandidateArray ) -> Self {
729+ Self {
730+ candidates,
731+ error : ptr:: null ( ) ,
732+ }
733+ }
734+
735+ fn error ( message : & str ) -> Self {
736+ Self {
737+ candidates : ptr:: null_mut ( ) ,
738+ error : CString :: new ( message)
739+ . map ( |s| s. into_raw ( ) . cast_const ( ) )
740+ . unwrap_or ( ptr:: null ( ) ) ,
741+ }
742+ }
743+ }
744+
745+ /// Runs completion for the given receiver and returns a structured result with candidates or an error message
719746fn run_and_finalize_completion (
720747 graph : & mut Graph ,
721748 receiver : CompletionReceiver ,
722749 names_to_untrack : Vec < NameId > ,
723- ) -> * mut CompletionCandidateArray {
724- let Ok ( candidates) = query:: completion_candidates ( graph, CompletionContext :: new ( receiver) ) else {
725- for name_id in names_to_untrack {
726- graph. untrack_name ( name_id) ;
750+ ) -> CompletionResult {
751+ let candidates = match query:: completion_candidates ( graph, CompletionContext :: new ( receiver) ) {
752+ Ok ( candidates) => candidates,
753+ Err ( e) => {
754+ for name_id in names_to_untrack {
755+ graph. untrack_name ( name_id) ;
756+ }
757+ return CompletionResult :: error ( & e. to_string ( ) ) ;
727758 }
728- return ptr:: null_mut ( ) ;
729759 } ;
730760
731761 let entries: Vec < CCompletionCandidate > = candidates
732762 . into_iter ( )
733- . filter_map ( |candidate| {
734- Some ( match candidate {
735- CompletionCandidate :: Declaration ( id) => {
736- let decl = graph. declarations ( ) . get ( & id) ?;
737- CCompletionCandidate {
738- kind : CCompletionCandidateKind :: Declaration ,
739- declaration : Box :: into_raw ( Box :: new ( CDeclaration :: from_declaration ( id, decl) ) ) ,
740- name : ptr:: null ( ) ,
741- documentation : ptr:: null ( ) ,
742- }
763+ . map ( |candidate| match candidate {
764+ CompletionCandidate :: Declaration ( id) => {
765+ let decl = graph
766+ . declarations ( )
767+ . get ( & id)
768+ . expect ( "completion candidate declaration must exist in graph" ) ;
769+ CCompletionCandidate {
770+ kind : CCompletionCandidateKind :: Declaration ,
771+ declaration : Box :: into_raw ( Box :: new ( CDeclaration :: from_declaration ( id, decl) ) ) ,
772+ name : ptr:: null ( ) ,
773+ documentation : ptr:: null ( ) ,
743774 }
744- CompletionCandidate :: Keyword ( kw) => CCompletionCandidate {
745- kind : CCompletionCandidateKind :: Keyword ,
775+ }
776+ CompletionCandidate :: Keyword ( kw) => CCompletionCandidate {
777+ kind : CCompletionCandidateKind :: Keyword ,
778+ declaration : ptr:: null ( ) ,
779+ name : CString :: new ( kw. name ( ) )
780+ . expect ( "keyword name must not contain NUL" )
781+ . into_raw ( )
782+ . cast_const ( ) ,
783+ documentation : CString :: new ( kw. documentation ( ) )
784+ . expect ( "keyword documentation must not contain NUL" )
785+ . into_raw ( )
786+ . cast_const ( ) ,
787+ } ,
788+ CompletionCandidate :: KeywordArgument ( str_id) => {
789+ let name_str = graph
790+ . strings ( )
791+ . get ( & str_id)
792+ . expect ( "keyword argument string must exist in graph" ) ;
793+ CCompletionCandidate {
794+ kind : CCompletionCandidateKind :: KeywordParameter ,
746795 declaration : ptr:: null ( ) ,
747- name : CString :: new ( kw. name ( ) ) . ok ( ) ?. into_raw ( ) . cast_const ( ) ,
748- documentation : CString :: new ( kw. documentation ( ) ) . ok ( ) ?. into_raw ( ) . cast_const ( ) ,
749- } ,
750- CompletionCandidate :: KeywordArgument ( str_id) => {
751- let name_str = graph. strings ( ) . get ( & str_id) ?;
752- CCompletionCandidate {
753- kind : CCompletionCandidateKind :: KeywordParameter ,
754- declaration : ptr:: null ( ) ,
755- name : CString :: new ( name_str. as_str ( ) ) . ok ( ) ?. into_raw ( ) . cast_const ( ) ,
756- documentation : ptr:: null ( ) ,
757- }
796+ name : CString :: new ( name_str. as_str ( ) )
797+ . expect ( "keyword argument name must not contain NUL" )
798+ . into_raw ( )
799+ . cast_const ( ) ,
800+ documentation : ptr:: null ( ) ,
758801 }
759- } )
802+ }
760803 } )
761804 . collect ( ) ;
762805
763806 for name_id in names_to_untrack {
764807 graph. untrack_name ( name_id) ;
765808 }
766809
767- CompletionCandidateArray :: from_vec ( entries)
810+ CompletionResult :: success ( CompletionCandidateArray :: from_vec ( entries) )
768811}
769812
770813/// Returns expression completion candidates.
771- /// The caller must free the result with `rdx_completion_candidates_free`.
814+ /// The caller must free candidates with `rdx_completion_candidates_free`
815+ /// and the error string (if non-null) with `free_c_string`.
772816///
773817/// # Safety
774818///
@@ -779,19 +823,20 @@ pub unsafe extern "C" fn rdx_graph_complete_expression(
779823 pointer : GraphPointer ,
780824 nesting : * const * const c_char ,
781825 nesting_count : usize ,
782- ) -> * mut CompletionCandidateArray {
826+ ) -> CompletionResult {
783827 with_mut_graph ( pointer, |graph| {
784828 let Ok ( ( name_id, names_to_untrack) ) = ( unsafe { completion_nesting_name_id ( graph, nesting, nesting_count) } )
785829 else {
786- return ptr:: null_mut ( ) ;
830+ return CompletionResult :: success ( ptr:: null_mut ( ) ) ;
787831 } ;
788832
789833 run_and_finalize_completion ( graph, CompletionReceiver :: Expression ( name_id) , names_to_untrack)
790834 } )
791835}
792836
793837/// Returns namespace access completion candidates.
794- /// The caller must free the result with `rdx_completion_candidates_free`.
838+ /// The caller must free candidates with `rdx_completion_candidates_free`
839+ /// and the error string (if non-null) with `free_c_string`.
795840///
796841/// # Safety
797842///
@@ -801,9 +846,9 @@ pub unsafe extern "C" fn rdx_graph_complete_expression(
801846pub unsafe extern "C" fn rdx_graph_complete_namespace_access (
802847 pointer : GraphPointer ,
803848 name : * const c_char ,
804- ) -> * mut CompletionCandidateArray {
849+ ) -> CompletionResult {
805850 let Ok ( name_str) = ( unsafe { utils:: convert_char_ptr_to_string ( name) } ) else {
806- return ptr:: null_mut ( ) ;
851+ return CompletionResult :: success ( ptr:: null_mut ( ) ) ;
807852 } ;
808853
809854 with_mut_graph ( pointer, |graph| {
@@ -816,7 +861,8 @@ pub unsafe extern "C" fn rdx_graph_complete_namespace_access(
816861}
817862
818863/// Returns method call completion candidates.
819- /// The caller must free the result with `rdx_completion_candidates_free`.
864+ /// The caller must free candidates with `rdx_completion_candidates_free`
865+ /// and the error string (if non-null) with `free_c_string`.
820866///
821867/// # Safety
822868///
@@ -826,9 +872,9 @@ pub unsafe extern "C" fn rdx_graph_complete_namespace_access(
826872pub unsafe extern "C" fn rdx_graph_complete_method_call (
827873 pointer : GraphPointer ,
828874 name : * const c_char ,
829- ) -> * mut CompletionCandidateArray {
875+ ) -> CompletionResult {
830876 let Ok ( name_str) = ( unsafe { utils:: convert_char_ptr_to_string ( name) } ) else {
831- return ptr:: null_mut ( ) ;
877+ return CompletionResult :: success ( ptr:: null_mut ( ) ) ;
832878 } ;
833879
834880 with_mut_graph ( pointer, |graph| {
@@ -841,7 +887,8 @@ pub unsafe extern "C" fn rdx_graph_complete_method_call(
841887}
842888
843889/// Returns method argument completion candidates.
844- /// The caller must free the result with `rdx_completion_candidates_free`.
890+ /// The caller must free candidates with `rdx_completion_candidates_free`
891+ /// and the error string (if non-null) with `free_c_string`.
845892///
846893/// # Safety
847894///
@@ -854,16 +901,16 @@ pub unsafe extern "C" fn rdx_graph_complete_method_argument(
854901 name : * const c_char ,
855902 nesting : * const * const c_char ,
856903 nesting_count : usize ,
857- ) -> * mut CompletionCandidateArray {
904+ ) -> CompletionResult {
858905 let Ok ( name_str) = ( unsafe { utils:: convert_char_ptr_to_string ( name) } ) else {
859- return ptr:: null_mut ( ) ;
906+ return CompletionResult :: success ( ptr:: null_mut ( ) ) ;
860907 } ;
861908
862909 with_mut_graph ( pointer, |graph| {
863910 let Ok ( ( self_name_id, names_to_untrack) ) =
864911 ( unsafe { completion_nesting_name_id ( graph, nesting, nesting_count) } )
865912 else {
866- return ptr:: null_mut ( ) ;
913+ return CompletionResult :: success ( ptr:: null_mut ( ) ) ;
867914 } ;
868915
869916 run_and_finalize_completion (
0 commit comments