// This file is auto-generated by alef — DO NOT EDIT. // alef:hash:4e15143f4af1ae8bafbdb1506ef057da924484c66a19483966333558ad437e75 // To regenerate: alef generate // To verify freshness: alef verify --exit-code // Issues & docs: https://github.com/kreuzberg-dev/alef package kreuzberg /* #cgo CFLAGS: -I${SRCDIR}/include #include "kreuzberg.h" #include #include extern int32_t goOcrBackendProcessImage(void* user_data, uint8_t* image_bytes, size_t image_bytes_len, char* config, char** out_result, char** out_error); extern int32_t goOcrBackendProcessImageFile(void* user_data, char* path, char* config, char** out_result, char** out_error); extern int32_t goOcrBackendSupportsLanguage(void* user_data, char* lang, char** out_result, char** out_error); extern int32_t goOcrBackendBackendType(void* user_data, char** out_result, char** out_error); extern int32_t goOcrBackendSupportedLanguages(void* user_data, char** out_result, char** out_error); extern int32_t goOcrBackendSupportsTableDetection(void* user_data, char** out_result, char** out_error); extern int32_t goOcrBackendSupportsDocumentProcessing(void* user_data, char** out_result, char** out_error); extern int32_t goOcrBackendProcessDocument(void* user_data, char* _path, char* _config, char** out_result, char** out_error); extern int32_t goOcrBackendName(void*, char**, char**); extern int32_t goOcrBackendVersion(void*, char**, char**); extern int32_t goOcrBackendInitialize(void*, char**); extern int32_t goOcrBackendShutdown(void*, char**); extern void goOcrBackendFreeUserData(void*); extern void goOcrBackendFreeString(char*); extern int32_t goPostProcessorProcess(void* user_data, char* result, char* config, char** out_error); extern int32_t goPostProcessorProcessingStage(void* user_data, char** out_result, char** out_error); extern int32_t goPostProcessorShouldProcess(void* user_data, char* _result, char* _config, char** out_result, char** out_error); extern int32_t goPostProcessorEstimatedDurationMs(void* user_data, char* _result, char** out_result, char** out_error); extern int32_t goPostProcessorPriority(void* user_data, char** out_result, char** out_error); extern int32_t goPostProcessorName(void*, char**, char**); extern int32_t goPostProcessorVersion(void*, char**, char**); extern int32_t goPostProcessorInitialize(void*, char**); extern int32_t goPostProcessorShutdown(void*, char**); extern void goPostProcessorFreeUserData(void*); extern void goPostProcessorFreeString(char*); extern int32_t goValidatorValidate(void* user_data, char* result, char* config, char** out_error); extern int32_t goValidatorShouldValidate(void* user_data, char* _result, char* _config, char** out_result, char** out_error); extern int32_t goValidatorPriority(void* user_data, char** out_result, char** out_error); extern int32_t goValidatorName(void*, char**, char**); extern int32_t goValidatorVersion(void*, char**, char**); extern int32_t goValidatorInitialize(void*, char**); extern int32_t goValidatorShutdown(void*, char**); extern void goValidatorFreeUserData(void*); extern void goValidatorFreeString(char*); extern int32_t goEmbeddingBackendDimensions(void* user_data, char** out_result, char** out_error); extern int32_t goEmbeddingBackendEmbed(void* user_data, char* texts, char** out_result, char** out_error); extern int32_t goEmbeddingBackendName(void*, char**, char**); extern int32_t goEmbeddingBackendVersion(void*, char**, char**); extern int32_t goEmbeddingBackendInitialize(void*, char**); extern int32_t goEmbeddingBackendShutdown(void*, char**); extern void goEmbeddingBackendFreeUserData(void*); extern void goEmbeddingBackendFreeString(char*); extern int32_t goDocumentExtractorExtractBytes(void* user_data, uint8_t* content, size_t content_len, char* mime_type, char* config, char** out_result, char** out_error); extern int32_t goDocumentExtractorExtractFile(void* user_data, char* path, char* mime_type, char* config, char** out_result, char** out_error); extern int32_t goDocumentExtractorSupportedMimeTypes(void* user_data, char** out_result, char** out_error); extern int32_t goDocumentExtractorPriority(void* user_data, char** out_result, char** out_error); extern int32_t goDocumentExtractorCanHandle(void* user_data, char* _path, char* _mime_type, char** out_result, char** out_error); extern int32_t goDocumentExtractorName(void*, char**, char**); extern int32_t goDocumentExtractorVersion(void*, char**, char**); extern int32_t goDocumentExtractorInitialize(void*, char**); extern int32_t goDocumentExtractorShutdown(void*, char**); extern void goDocumentExtractorFreeUserData(void*); extern void goDocumentExtractorFreeString(char*); extern int32_t goRendererRender(void* user_data, char* doc, char** out_result, char** out_error); extern int32_t goRendererName(void*, char**, char**); extern int32_t goRendererVersion(void*, char**, char**); extern int32_t goRendererInitialize(void*, char**); extern int32_t goRendererShutdown(void*, char**); extern void goRendererFreeUserData(void*); extern void goRendererFreeString(char*); */ import "C" import ( "encoding/json" "fmt" "runtime/cgo" "sync" "unsafe" ) // handleRegistry tracks cgo.Handles by name to ensure proper cleanup on unregister. // Without this, unregistered plugins can cause use-after-free crashes when Rust // still holds vtable pointers and tries to invoke callbacks on deleted handles. type handleRegistry struct { mu sync.Mutex handles map[string]cgo.Handle } var ( ocr_backendRegistry = &handleRegistry{handles: make(map[string]cgo.Handle)} post_processorRegistry = &handleRegistry{handles: make(map[string]cgo.Handle)} validatorRegistry = &handleRegistry{handles: make(map[string]cgo.Handle)} embedding_backendRegistry = &handleRegistry{handles: make(map[string]cgo.Handle)} document_extractorRegistry = &handleRegistry{handles: make(map[string]cgo.Handle)} rendererRegistry = &handleRegistry{handles: make(map[string]cgo.Handle)} ) // store adds a handle to the registry, keyed by name. func (reg *handleRegistry) store(name string, handle cgo.Handle) { reg.mu.Lock() defer reg.mu.Unlock() if old, ok := reg.handles[name]; ok { old.Delete() } reg.handles[name] = handle } // delete removes and deletes a handle from the registry by name. func (reg *handleRegistry) delete(name string) { reg.mu.Lock() defer reg.mu.Unlock() if handle, ok := reg.handles[name]; ok { delete(reg.handles, name) handle.Delete() } } // clear removes and deletes all handles from the registry. func (reg *handleRegistry) clear() { reg.mu.Lock() defer reg.mu.Unlock() for _, handle := range reg.handles { handle.Delete() } reg.handles = make(map[string]cgo.Handle) } // OcrBackend defines the Go interface for the OcrBackend trait. type OcrBackend interface { // Name returns the plugin name. Name() string // Version returns the plugin version. Version() string // Initialize is called when the plugin is loaded. Initialize() error // Shutdown is called when the plugin is unloaded. Shutdown() error // process_image ProcessImage(image_bytes []byte, config OcrConfig) (ExtractionResult, error) // process_image_file ProcessImageFile(path string, config OcrConfig) (ExtractionResult, error) // supports_language SupportsLanguage(lang string) bool // backend_type BackendType() OcrBackendType // supported_languages SupportedLanguages() []string // supports_table_detection SupportsTableDetection() bool // supports_document_processing SupportsDocumentProcessing() bool // process_document ProcessDocument(_path string, _config OcrConfig) (ExtractionResult, error) } //export goOcrBackendProcessImage func goOcrBackendProcessImage( userData unsafe.Pointer, image_bytes *C.uint8_t, image_bytesLen C.size_t, config *C.char, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(OcrBackend) if !ok { return 1 // error: invalid handle } var goImage_bytes []byte if image_bytes != nil { goImage_bytes = unsafe.Slice((*byte)(unsafe.Pointer(image_bytes)), int(image_bytesLen)) } var goConfig OcrConfig if config != nil { json.Unmarshal([]byte(C.GoString(config)), &goConfig) } // Call the method result, err := impl.ProcessImage(goImage_bytes, goConfig) if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goOcrBackendProcessImageFile func goOcrBackendProcessImageFile( userData unsafe.Pointer, path *C.char, config *C.char, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(OcrBackend) if !ok { return 1 // error: invalid handle } goPath := C.GoString(path) var goConfig OcrConfig if config != nil { json.Unmarshal([]byte(C.GoString(config)), &goConfig) } // Call the method result, err := impl.ProcessImageFile(goPath, goConfig) if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goOcrBackendSupportsLanguage func goOcrBackendSupportsLanguage( userData unsafe.Pointer, lang *C.char, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(OcrBackend) if !ok { return 1 // error: invalid handle } goLang := C.GoString(lang) // Call the method result := impl.SupportsLanguage(goLang) jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goOcrBackendBackendType func goOcrBackendBackendType( userData unsafe.Pointer, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(OcrBackend) if !ok { return 1 // error: invalid handle } // Call the method result := impl.BackendType() jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goOcrBackendSupportedLanguages func goOcrBackendSupportedLanguages( userData unsafe.Pointer, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(OcrBackend) if !ok { return 1 // error: invalid handle } // Call the method result := impl.SupportedLanguages() jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goOcrBackendSupportsTableDetection func goOcrBackendSupportsTableDetection( userData unsafe.Pointer, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(OcrBackend) if !ok { return 1 // error: invalid handle } // Call the method result := impl.SupportsTableDetection() jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goOcrBackendSupportsDocumentProcessing func goOcrBackendSupportsDocumentProcessing( userData unsafe.Pointer, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(OcrBackend) if !ok { return 1 // error: invalid handle } // Call the method result := impl.SupportsDocumentProcessing() jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goOcrBackendProcessDocument func goOcrBackendProcessDocument( userData unsafe.Pointer, _path *C.char, _config *C.char, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(OcrBackend) if !ok { return 1 // error: invalid handle } go_path := C.GoString(_path) var go_config OcrConfig if _config != nil { json.Unmarshal([]byte(C.GoString(_config)), &go_config) } // Call the method result, err := impl.ProcessDocument(go_path, go_config) if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goOcrBackendName func goOcrBackendName(userData unsafe.Pointer, outResult **C.char, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(OcrBackend) if !ok { return 1 } name := impl.Name() cName := C.CString(name) *outResult = cName return 0 } //export goOcrBackendVersion func goOcrBackendVersion(userData unsafe.Pointer, outResult **C.char, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(OcrBackend) if !ok { return 1 } version := impl.Version() cVersion := C.CString(version) *outResult = cVersion return 0 } //export goOcrBackendInitialize func goOcrBackendInitialize(userData unsafe.Pointer, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(OcrBackend) if !ok { return 1 } err := impl.Initialize() if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 } //export goOcrBackendShutdown func goOcrBackendShutdown(userData unsafe.Pointer, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(OcrBackend) if !ok { return 1 } err := impl.Shutdown() if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 } //export goOcrBackendFreeUserData func goOcrBackendFreeUserData(userData unsafe.Pointer) { // No-op to avoid cleanup-queue panics. Handles cleaned in Unregister(). } //export goOcrBackendFreeString func goOcrBackendFreeString(ptr *C.char) { if ptr != nil { C.free(unsafe.Pointer(ptr)) } } // RegisterOcrBackend registers a OcrBackend implementation with the C runtime. func RegisterOcrBackend(impl OcrBackend) error { handle := cgo.NewHandle(impl) // Build the C vtable DEBUG:c_vtable_struct=KREUZBERGKreuzbergOcrBackendVTable vtable := C.KREUZBERGKreuzbergOcrBackendVTable{ process_image: (*[0]byte)(unsafe.Pointer(C.goOcrBackendProcessImage)), process_image_file: (*[0]byte)(unsafe.Pointer(C.goOcrBackendProcessImageFile)), supports_language: (*[0]byte)(unsafe.Pointer(C.goOcrBackendSupportsLanguage)), backend_type: (*[0]byte)(unsafe.Pointer(C.goOcrBackendBackendType)), supported_languages: (*[0]byte)(unsafe.Pointer(C.goOcrBackendSupportedLanguages)), supports_table_detection: (*[0]byte)(unsafe.Pointer(C.goOcrBackendSupportsTableDetection)), supports_document_processing: (*[0]byte)(unsafe.Pointer(C.goOcrBackendSupportsDocumentProcessing)), process_document: (*[0]byte)(unsafe.Pointer(C.goOcrBackendProcessDocument)), name_fn: (*[0]byte)(unsafe.Pointer(C.goOcrBackendName)), version_fn: (*[0]byte)(unsafe.Pointer(C.goOcrBackendVersion)), initialize_fn: (*[0]byte)(unsafe.Pointer(C.goOcrBackendInitialize)), shutdown_fn: (*[0]byte)(unsafe.Pointer(C.goOcrBackendShutdown)), free_string: (*[0]byte)(unsafe.Pointer(C.goOcrBackendFreeString)), free_user_data: (*[0]byte)(unsafe.Pointer(C.goOcrBackendFreeUserData)), } // Call C registration cName := C.CString(impl.Name()) defer C.free(unsafe.Pointer(cName)) var cErr *C.char rc := C.kreuzberg_register_ocr_backend( cName, vtable, unsafe.Pointer(uintptr(handle)), &cErr, ) if rc != 0 { msg := "failed to register OcrBackend" if cErr != nil { msg = C.GoString(cErr) C.kreuzberg_free_string(cErr) } handle.Delete() return fmt.Errorf("%s", msg) } // Store handle by name for later cleanup on unregister ocr_backendRegistry.store(impl.Name(), handle) return nil } // UnregisterOcrBackend unregisters a OcrBackend implementation. func UnregisterOcrBackend(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) var cErr *C.char rc := C.kreuzberg_unregister_ocr_backend(cName, &cErr) if rc != 0 { msg := "failed to unregister OcrBackend" if cErr != nil { msg = C.GoString(cErr) C.kreuzberg_free_string(cErr) } return fmt.Errorf("%s", msg) } // Delete the handle now that Rust has unregistered the plugin ocr_backendRegistry.delete(name) return nil } // ClearOcrBackends removes all registered OcrBackend implementations. func ClearOcrBackends() error { var cErr *C.char rc := C.kreuzberg_clear_ocr_backend(&cErr) if rc != 0 { msg := "failed to clear OcrBackend plugins" if cErr != nil { msg = C.GoString(cErr) C.free(unsafe.Pointer(cErr)) } return fmt.Errorf("%s", msg) } // Delete all handles now that Rust has cleared all plugins ocr_backendRegistry.clear() return nil } // PostProcessor defines the Go interface for the PostProcessor trait. type PostProcessor interface { // Name returns the plugin name. Name() string // Version returns the plugin version. Version() string // Initialize is called when the plugin is loaded. Initialize() error // Shutdown is called when the plugin is unloaded. Shutdown() error // process Process(result ExtractionResult, config ExtractionConfig) error // processing_stage ProcessingStage() ProcessingStage // should_process ShouldProcess(_result ExtractionResult, _config ExtractionConfig) bool // estimated_duration_ms EstimatedDurationMs(_result ExtractionResult) uint64 // priority Priority() int32 } //export goPostProcessorProcess func goPostProcessorProcess( userData unsafe.Pointer, result *C.char, config *C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(PostProcessor) if !ok { return 1 // error: invalid handle } var goResult ExtractionResult if result != nil { json.Unmarshal([]byte(C.GoString(result)), &goResult) } var goConfig ExtractionConfig if config != nil { json.Unmarshal([]byte(C.GoString(config)), &goConfig) } // Call the method err := impl.Process(goResult, goConfig) if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 // success } //export goPostProcessorProcessingStage func goPostProcessorProcessingStage( userData unsafe.Pointer, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(PostProcessor) if !ok { return 1 // error: invalid handle } // Call the method result := impl.ProcessingStage() jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goPostProcessorShouldProcess func goPostProcessorShouldProcess( userData unsafe.Pointer, _result *C.char, _config *C.char, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(PostProcessor) if !ok { return 1 // error: invalid handle } var go_result ExtractionResult if _result != nil { json.Unmarshal([]byte(C.GoString(_result)), &go_result) } var go_config ExtractionConfig if _config != nil { json.Unmarshal([]byte(C.GoString(_config)), &go_config) } // Call the method result := impl.ShouldProcess(go_result, go_config) jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goPostProcessorEstimatedDurationMs func goPostProcessorEstimatedDurationMs( userData unsafe.Pointer, _result *C.char, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(PostProcessor) if !ok { return 1 // error: invalid handle } var go_result ExtractionResult if _result != nil { json.Unmarshal([]byte(C.GoString(_result)), &go_result) } // Call the method result := impl.EstimatedDurationMs(go_result) jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goPostProcessorPriority func goPostProcessorPriority( userData unsafe.Pointer, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(PostProcessor) if !ok { return 1 // error: invalid handle } // Call the method result := impl.Priority() jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goPostProcessorName func goPostProcessorName(userData unsafe.Pointer, outResult **C.char, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(PostProcessor) if !ok { return 1 } name := impl.Name() cName := C.CString(name) *outResult = cName return 0 } //export goPostProcessorVersion func goPostProcessorVersion(userData unsafe.Pointer, outResult **C.char, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(PostProcessor) if !ok { return 1 } version := impl.Version() cVersion := C.CString(version) *outResult = cVersion return 0 } //export goPostProcessorInitialize func goPostProcessorInitialize(userData unsafe.Pointer, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(PostProcessor) if !ok { return 1 } err := impl.Initialize() if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 } //export goPostProcessorShutdown func goPostProcessorShutdown(userData unsafe.Pointer, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(PostProcessor) if !ok { return 1 } err := impl.Shutdown() if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 } //export goPostProcessorFreeUserData func goPostProcessorFreeUserData(userData unsafe.Pointer) { // No-op to avoid cleanup-queue panics. Handles cleaned in Unregister(). } //export goPostProcessorFreeString func goPostProcessorFreeString(ptr *C.char) { if ptr != nil { C.free(unsafe.Pointer(ptr)) } } // RegisterPostProcessor registers a PostProcessor implementation with the C runtime. func RegisterPostProcessor(impl PostProcessor) error { handle := cgo.NewHandle(impl) // Build the C vtable DEBUG:c_vtable_struct=KREUZBERGKreuzbergPostProcessorVTable vtable := C.KREUZBERGKreuzbergPostProcessorVTable{ process: (*[0]byte)(unsafe.Pointer(C.goPostProcessorProcess)), processing_stage: (*[0]byte)(unsafe.Pointer(C.goPostProcessorProcessingStage)), should_process: (*[0]byte)(unsafe.Pointer(C.goPostProcessorShouldProcess)), estimated_duration_ms: (*[0]byte)(unsafe.Pointer(C.goPostProcessorEstimatedDurationMs)), priority: (*[0]byte)(unsafe.Pointer(C.goPostProcessorPriority)), name_fn: (*[0]byte)(unsafe.Pointer(C.goPostProcessorName)), version_fn: (*[0]byte)(unsafe.Pointer(C.goPostProcessorVersion)), initialize_fn: (*[0]byte)(unsafe.Pointer(C.goPostProcessorInitialize)), shutdown_fn: (*[0]byte)(unsafe.Pointer(C.goPostProcessorShutdown)), free_string: (*[0]byte)(unsafe.Pointer(C.goPostProcessorFreeString)), free_user_data: (*[0]byte)(unsafe.Pointer(C.goPostProcessorFreeUserData)), } // Call C registration cName := C.CString(impl.Name()) defer C.free(unsafe.Pointer(cName)) var cErr *C.char rc := C.kreuzberg_register_post_processor( cName, vtable, unsafe.Pointer(uintptr(handle)), &cErr, ) if rc != 0 { msg := "failed to register PostProcessor" if cErr != nil { msg = C.GoString(cErr) C.kreuzberg_free_string(cErr) } handle.Delete() return fmt.Errorf("%s", msg) } // Store handle by name for later cleanup on unregister post_processorRegistry.store(impl.Name(), handle) return nil } // UnregisterPostProcessor unregisters a PostProcessor implementation. func UnregisterPostProcessor(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) var cErr *C.char rc := C.kreuzberg_unregister_post_processor(cName, &cErr) if rc != 0 { msg := "failed to unregister PostProcessor" if cErr != nil { msg = C.GoString(cErr) C.kreuzberg_free_string(cErr) } return fmt.Errorf("%s", msg) } // Delete the handle now that Rust has unregistered the plugin post_processorRegistry.delete(name) return nil } // ClearPostProcessors removes all registered PostProcessor implementations. func ClearPostProcessors() error { var cErr *C.char rc := C.kreuzberg_clear_post_processor(&cErr) if rc != 0 { msg := "failed to clear PostProcessor plugins" if cErr != nil { msg = C.GoString(cErr) C.free(unsafe.Pointer(cErr)) } return fmt.Errorf("%s", msg) } // Delete all handles now that Rust has cleared all plugins post_processorRegistry.clear() return nil } // Validator defines the Go interface for the Validator trait. type Validator interface { // Name returns the plugin name. Name() string // Version returns the plugin version. Version() string // Initialize is called when the plugin is loaded. Initialize() error // Shutdown is called when the plugin is unloaded. Shutdown() error // validate Validate(result ExtractionResult, config ExtractionConfig) error // should_validate ShouldValidate(_result ExtractionResult, _config ExtractionConfig) bool // priority Priority() int32 } //export goValidatorValidate func goValidatorValidate( userData unsafe.Pointer, result *C.char, config *C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(Validator) if !ok { return 1 // error: invalid handle } var goResult ExtractionResult if result != nil { json.Unmarshal([]byte(C.GoString(result)), &goResult) } var goConfig ExtractionConfig if config != nil { json.Unmarshal([]byte(C.GoString(config)), &goConfig) } // Call the method err := impl.Validate(goResult, goConfig) if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 // success } //export goValidatorShouldValidate func goValidatorShouldValidate( userData unsafe.Pointer, _result *C.char, _config *C.char, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(Validator) if !ok { return 1 // error: invalid handle } var go_result ExtractionResult if _result != nil { json.Unmarshal([]byte(C.GoString(_result)), &go_result) } var go_config ExtractionConfig if _config != nil { json.Unmarshal([]byte(C.GoString(_config)), &go_config) } // Call the method result := impl.ShouldValidate(go_result, go_config) jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goValidatorPriority func goValidatorPriority( userData unsafe.Pointer, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(Validator) if !ok { return 1 // error: invalid handle } // Call the method result := impl.Priority() jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goValidatorName func goValidatorName(userData unsafe.Pointer, outResult **C.char, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(Validator) if !ok { return 1 } name := impl.Name() cName := C.CString(name) *outResult = cName return 0 } //export goValidatorVersion func goValidatorVersion(userData unsafe.Pointer, outResult **C.char, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(Validator) if !ok { return 1 } version := impl.Version() cVersion := C.CString(version) *outResult = cVersion return 0 } //export goValidatorInitialize func goValidatorInitialize(userData unsafe.Pointer, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(Validator) if !ok { return 1 } err := impl.Initialize() if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 } //export goValidatorShutdown func goValidatorShutdown(userData unsafe.Pointer, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(Validator) if !ok { return 1 } err := impl.Shutdown() if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 } //export goValidatorFreeUserData func goValidatorFreeUserData(userData unsafe.Pointer) { // No-op to avoid cleanup-queue panics. Handles cleaned in Unregister(). } //export goValidatorFreeString func goValidatorFreeString(ptr *C.char) { if ptr != nil { C.free(unsafe.Pointer(ptr)) } } // RegisterValidator registers a Validator implementation with the C runtime. func RegisterValidator(impl Validator) error { handle := cgo.NewHandle(impl) // Build the C vtable DEBUG:c_vtable_struct=KREUZBERGKreuzbergValidatorVTable vtable := C.KREUZBERGKreuzbergValidatorVTable{ validate: (*[0]byte)(unsafe.Pointer(C.goValidatorValidate)), should_validate: (*[0]byte)(unsafe.Pointer(C.goValidatorShouldValidate)), priority: (*[0]byte)(unsafe.Pointer(C.goValidatorPriority)), name_fn: (*[0]byte)(unsafe.Pointer(C.goValidatorName)), version_fn: (*[0]byte)(unsafe.Pointer(C.goValidatorVersion)), initialize_fn: (*[0]byte)(unsafe.Pointer(C.goValidatorInitialize)), shutdown_fn: (*[0]byte)(unsafe.Pointer(C.goValidatorShutdown)), free_string: (*[0]byte)(unsafe.Pointer(C.goValidatorFreeString)), free_user_data: (*[0]byte)(unsafe.Pointer(C.goValidatorFreeUserData)), } // Call C registration cName := C.CString(impl.Name()) defer C.free(unsafe.Pointer(cName)) var cErr *C.char rc := C.kreuzberg_register_validator( cName, vtable, unsafe.Pointer(uintptr(handle)), &cErr, ) if rc != 0 { msg := "failed to register Validator" if cErr != nil { msg = C.GoString(cErr) C.kreuzberg_free_string(cErr) } handle.Delete() return fmt.Errorf("%s", msg) } // Store handle by name for later cleanup on unregister validatorRegistry.store(impl.Name(), handle) return nil } // UnregisterValidator unregisters a Validator implementation. func UnregisterValidator(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) var cErr *C.char rc := C.kreuzberg_unregister_validator(cName, &cErr) if rc != 0 { msg := "failed to unregister Validator" if cErr != nil { msg = C.GoString(cErr) C.kreuzberg_free_string(cErr) } return fmt.Errorf("%s", msg) } // Delete the handle now that Rust has unregistered the plugin validatorRegistry.delete(name) return nil } // ClearValidators removes all registered Validator implementations. func ClearValidators() error { var cErr *C.char rc := C.kreuzberg_clear_validator(&cErr) if rc != 0 { msg := "failed to clear Validator plugins" if cErr != nil { msg = C.GoString(cErr) C.free(unsafe.Pointer(cErr)) } return fmt.Errorf("%s", msg) } // Delete all handles now that Rust has cleared all plugins validatorRegistry.clear() return nil } // EmbeddingBackend defines the Go interface for the EmbeddingBackend trait. type EmbeddingBackend interface { // Name returns the plugin name. Name() string // Version returns the plugin version. Version() string // Initialize is called when the plugin is loaded. Initialize() error // Shutdown is called when the plugin is unloaded. Shutdown() error // dimensions Dimensions() uint // embed Embed(texts []string) ([][]float32, error) } //export goEmbeddingBackendDimensions func goEmbeddingBackendDimensions( userData unsafe.Pointer, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(EmbeddingBackend) if !ok { return 1 // error: invalid handle } // Call the method result := impl.Dimensions() jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goEmbeddingBackendEmbed func goEmbeddingBackendEmbed( userData unsafe.Pointer, texts *C.char, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(EmbeddingBackend) if !ok { return 1 // error: invalid handle } var goTexts []string if texts != nil { json.Unmarshal([]byte(C.GoString(texts)), &goTexts) } // Call the method result, err := impl.Embed(goTexts) if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goEmbeddingBackendName func goEmbeddingBackendName(userData unsafe.Pointer, outResult **C.char, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(EmbeddingBackend) if !ok { return 1 } name := impl.Name() cName := C.CString(name) *outResult = cName return 0 } //export goEmbeddingBackendVersion func goEmbeddingBackendVersion(userData unsafe.Pointer, outResult **C.char, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(EmbeddingBackend) if !ok { return 1 } version := impl.Version() cVersion := C.CString(version) *outResult = cVersion return 0 } //export goEmbeddingBackendInitialize func goEmbeddingBackendInitialize(userData unsafe.Pointer, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(EmbeddingBackend) if !ok { return 1 } err := impl.Initialize() if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 } //export goEmbeddingBackendShutdown func goEmbeddingBackendShutdown(userData unsafe.Pointer, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(EmbeddingBackend) if !ok { return 1 } err := impl.Shutdown() if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 } //export goEmbeddingBackendFreeUserData func goEmbeddingBackendFreeUserData(userData unsafe.Pointer) { // No-op to avoid cleanup-queue panics. Handles cleaned in Unregister(). } //export goEmbeddingBackendFreeString func goEmbeddingBackendFreeString(ptr *C.char) { if ptr != nil { C.free(unsafe.Pointer(ptr)) } } // RegisterEmbeddingBackend registers a EmbeddingBackend implementation with the C runtime. func RegisterEmbeddingBackend(impl EmbeddingBackend) error { handle := cgo.NewHandle(impl) // Build the C vtable DEBUG:c_vtable_struct=KREUZBERGKreuzbergEmbeddingBackendVTable vtable := C.KREUZBERGKreuzbergEmbeddingBackendVTable{ dimensions: (*[0]byte)(unsafe.Pointer(C.goEmbeddingBackendDimensions)), embed: (*[0]byte)(unsafe.Pointer(C.goEmbeddingBackendEmbed)), name_fn: (*[0]byte)(unsafe.Pointer(C.goEmbeddingBackendName)), version_fn: (*[0]byte)(unsafe.Pointer(C.goEmbeddingBackendVersion)), initialize_fn: (*[0]byte)(unsafe.Pointer(C.goEmbeddingBackendInitialize)), shutdown_fn: (*[0]byte)(unsafe.Pointer(C.goEmbeddingBackendShutdown)), free_string: (*[0]byte)(unsafe.Pointer(C.goEmbeddingBackendFreeString)), free_user_data: (*[0]byte)(unsafe.Pointer(C.goEmbeddingBackendFreeUserData)), } // Call C registration cName := C.CString(impl.Name()) defer C.free(unsafe.Pointer(cName)) var cErr *C.char rc := C.kreuzberg_register_embedding_backend( cName, vtable, unsafe.Pointer(uintptr(handle)), &cErr, ) if rc != 0 { msg := "failed to register EmbeddingBackend" if cErr != nil { msg = C.GoString(cErr) C.kreuzberg_free_string(cErr) } handle.Delete() return fmt.Errorf("%s", msg) } // Store handle by name for later cleanup on unregister embedding_backendRegistry.store(impl.Name(), handle) return nil } // UnregisterEmbeddingBackend unregisters a EmbeddingBackend implementation. func UnregisterEmbeddingBackend(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) var cErr *C.char rc := C.kreuzberg_unregister_embedding_backend(cName, &cErr) if rc != 0 { msg := "failed to unregister EmbeddingBackend" if cErr != nil { msg = C.GoString(cErr) C.kreuzberg_free_string(cErr) } return fmt.Errorf("%s", msg) } // Delete the handle now that Rust has unregistered the plugin embedding_backendRegistry.delete(name) return nil } // ClearEmbeddingBackends removes all registered EmbeddingBackend implementations. func ClearEmbeddingBackends() error { var cErr *C.char rc := C.kreuzberg_clear_embedding_backend(&cErr) if rc != 0 { msg := "failed to clear EmbeddingBackend plugins" if cErr != nil { msg = C.GoString(cErr) C.free(unsafe.Pointer(cErr)) } return fmt.Errorf("%s", msg) } // Delete all handles now that Rust has cleared all plugins embedding_backendRegistry.clear() return nil } // DocumentExtractor defines the Go interface for the DocumentExtractor trait. type DocumentExtractor interface { // Name returns the plugin name. Name() string // Version returns the plugin version. Version() string // Initialize is called when the plugin is loaded. Initialize() error // Shutdown is called when the plugin is unloaded. Shutdown() error // extract_bytes ExtractBytes(content []byte, mime_type string, config ExtractionConfig) (json.RawMessage, error) // extract_file ExtractFile(path string, mime_type string, config ExtractionConfig) (json.RawMessage, error) // supported_mime_types SupportedMimeTypes() []string // priority Priority() int32 // can_handle CanHandle(_path string, _mime_type string) bool } //export goDocumentExtractorExtractBytes func goDocumentExtractorExtractBytes( userData unsafe.Pointer, content *C.uint8_t, contentLen C.size_t, mime_type *C.char, config *C.char, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(DocumentExtractor) if !ok { return 1 // error: invalid handle } var goContent []byte if content != nil { goContent = unsafe.Slice((*byte)(unsafe.Pointer(content)), int(contentLen)) } goMime_type := C.GoString(mime_type) var goConfig ExtractionConfig if config != nil { json.Unmarshal([]byte(C.GoString(config)), &goConfig) } // Call the method result, err := impl.ExtractBytes(goContent, goMime_type, goConfig) if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } cResult := C.CString(string(result)) *outResult = cResult return 0 // success } //export goDocumentExtractorExtractFile func goDocumentExtractorExtractFile( userData unsafe.Pointer, path *C.char, mime_type *C.char, config *C.char, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(DocumentExtractor) if !ok { return 1 // error: invalid handle } goPath := C.GoString(path) goMime_type := C.GoString(mime_type) var goConfig ExtractionConfig if config != nil { json.Unmarshal([]byte(C.GoString(config)), &goConfig) } // Call the method result, err := impl.ExtractFile(goPath, goMime_type, goConfig) if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } cResult := C.CString(string(result)) *outResult = cResult return 0 // success } //export goDocumentExtractorSupportedMimeTypes func goDocumentExtractorSupportedMimeTypes( userData unsafe.Pointer, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(DocumentExtractor) if !ok { return 1 // error: invalid handle } // Call the method result := impl.SupportedMimeTypes() jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goDocumentExtractorPriority func goDocumentExtractorPriority( userData unsafe.Pointer, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(DocumentExtractor) if !ok { return 1 // error: invalid handle } // Call the method result := impl.Priority() jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goDocumentExtractorCanHandle func goDocumentExtractorCanHandle( userData unsafe.Pointer, _path *C.char, _mime_type *C.char, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(DocumentExtractor) if !ok { return 1 // error: invalid handle } go_path := C.GoString(_path) go_mime_type := C.GoString(_mime_type) // Call the method result := impl.CanHandle(go_path, go_mime_type) jsonBytes, _ := json.Marshal(result) cResult := C.CString(string(jsonBytes)) *outResult = cResult return 0 // success } //export goDocumentExtractorName func goDocumentExtractorName(userData unsafe.Pointer, outResult **C.char, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(DocumentExtractor) if !ok { return 1 } name := impl.Name() cName := C.CString(name) *outResult = cName return 0 } //export goDocumentExtractorVersion func goDocumentExtractorVersion(userData unsafe.Pointer, outResult **C.char, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(DocumentExtractor) if !ok { return 1 } version := impl.Version() cVersion := C.CString(version) *outResult = cVersion return 0 } //export goDocumentExtractorInitialize func goDocumentExtractorInitialize(userData unsafe.Pointer, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(DocumentExtractor) if !ok { return 1 } err := impl.Initialize() if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 } //export goDocumentExtractorShutdown func goDocumentExtractorShutdown(userData unsafe.Pointer, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(DocumentExtractor) if !ok { return 1 } err := impl.Shutdown() if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 } //export goDocumentExtractorFreeUserData func goDocumentExtractorFreeUserData(userData unsafe.Pointer) { // No-op to avoid cleanup-queue panics. Handles cleaned in Unregister(). } //export goDocumentExtractorFreeString func goDocumentExtractorFreeString(ptr *C.char) { if ptr != nil { C.free(unsafe.Pointer(ptr)) } } // RegisterDocumentExtractor registers a DocumentExtractor implementation with the C runtime. func RegisterDocumentExtractor(impl DocumentExtractor) error { handle := cgo.NewHandle(impl) // Build the C vtable DEBUG:c_vtable_struct=KREUZBERGKreuzbergDocumentExtractorVTable vtable := C.KREUZBERGKreuzbergDocumentExtractorVTable{ extract_bytes: (*[0]byte)(unsafe.Pointer(C.goDocumentExtractorExtractBytes)), extract_file: (*[0]byte)(unsafe.Pointer(C.goDocumentExtractorExtractFile)), supported_mime_types: (*[0]byte)(unsafe.Pointer(C.goDocumentExtractorSupportedMimeTypes)), priority: (*[0]byte)(unsafe.Pointer(C.goDocumentExtractorPriority)), can_handle: (*[0]byte)(unsafe.Pointer(C.goDocumentExtractorCanHandle)), name_fn: (*[0]byte)(unsafe.Pointer(C.goDocumentExtractorName)), version_fn: (*[0]byte)(unsafe.Pointer(C.goDocumentExtractorVersion)), initialize_fn: (*[0]byte)(unsafe.Pointer(C.goDocumentExtractorInitialize)), shutdown_fn: (*[0]byte)(unsafe.Pointer(C.goDocumentExtractorShutdown)), free_string: (*[0]byte)(unsafe.Pointer(C.goDocumentExtractorFreeString)), free_user_data: (*[0]byte)(unsafe.Pointer(C.goDocumentExtractorFreeUserData)), } // Call C registration cName := C.CString(impl.Name()) defer C.free(unsafe.Pointer(cName)) var cErr *C.char rc := C.kreuzberg_register_document_extractor( cName, vtable, unsafe.Pointer(uintptr(handle)), &cErr, ) if rc != 0 { msg := "failed to register DocumentExtractor" if cErr != nil { msg = C.GoString(cErr) C.kreuzberg_free_string(cErr) } handle.Delete() return fmt.Errorf("%s", msg) } // Store handle by name for later cleanup on unregister document_extractorRegistry.store(impl.Name(), handle) return nil } // UnregisterDocumentExtractor unregisters a DocumentExtractor implementation. func UnregisterDocumentExtractor(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) var cErr *C.char rc := C.kreuzberg_unregister_document_extractor(cName, &cErr) if rc != 0 { msg := "failed to unregister DocumentExtractor" if cErr != nil { msg = C.GoString(cErr) C.kreuzberg_free_string(cErr) } return fmt.Errorf("%s", msg) } // Delete the handle now that Rust has unregistered the plugin document_extractorRegistry.delete(name) return nil } // ClearDocumentExtractors removes all registered DocumentExtractor implementations. func ClearDocumentExtractors() error { var cErr *C.char rc := C.kreuzberg_clear_document_extractor(&cErr) if rc != 0 { msg := "failed to clear DocumentExtractor plugins" if cErr != nil { msg = C.GoString(cErr) C.free(unsafe.Pointer(cErr)) } return fmt.Errorf("%s", msg) } // Delete all handles now that Rust has cleared all plugins document_extractorRegistry.clear() return nil } // Renderer defines the Go interface for the Renderer trait. type Renderer interface { // Name returns the plugin name. Name() string // Version returns the plugin version. Version() string // Initialize is called when the plugin is loaded. Initialize() error // Shutdown is called when the plugin is unloaded. Shutdown() error // render Render(doc json.RawMessage) (string, error) } //export goRendererRender func goRendererRender( userData unsafe.Pointer, doc *C.char, outResult **C.char, outError **C.char, ) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(Renderer) if !ok { return 1 // error: invalid handle } var goDoc json.RawMessage if doc != nil { goDoc = json.RawMessage(C.GoString(doc)) } // Call the method result, err := impl.Render(goDoc) if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } cResult := C.CString(result) *outResult = cResult return 0 // success } //export goRendererName func goRendererName(userData unsafe.Pointer, outResult **C.char, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(Renderer) if !ok { return 1 } name := impl.Name() cName := C.CString(name) *outResult = cName return 0 } //export goRendererVersion func goRendererVersion(userData unsafe.Pointer, outResult **C.char, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(Renderer) if !ok { return 1 } version := impl.Version() cVersion := C.CString(version) *outResult = cVersion return 0 } //export goRendererInitialize func goRendererInitialize(userData unsafe.Pointer, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(Renderer) if !ok { return 1 } err := impl.Initialize() if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 } //export goRendererShutdown func goRendererShutdown(userData unsafe.Pointer, outError **C.char) C.int32_t { handle := cgo.Handle(uintptr(unsafe.Pointer(userData))) impl, ok := handle.Value().(Renderer) if !ok { return 1 } err := impl.Shutdown() if err != nil { cErr := C.CString(err.Error()) *outError = cErr return 1 } return 0 } //export goRendererFreeUserData func goRendererFreeUserData(userData unsafe.Pointer) { // No-op to avoid cleanup-queue panics. Handles cleaned in Unregister(). } //export goRendererFreeString func goRendererFreeString(ptr *C.char) { if ptr != nil { C.free(unsafe.Pointer(ptr)) } } // RegisterRenderer registers a Renderer implementation with the C runtime. func RegisterRenderer(impl Renderer) error { handle := cgo.NewHandle(impl) // Build the C vtable DEBUG:c_vtable_struct=KREUZBERGKreuzbergRendererVTable vtable := C.KREUZBERGKreuzbergRendererVTable{ render: (*[0]byte)(unsafe.Pointer(C.goRendererRender)), name_fn: (*[0]byte)(unsafe.Pointer(C.goRendererName)), version_fn: (*[0]byte)(unsafe.Pointer(C.goRendererVersion)), initialize_fn: (*[0]byte)(unsafe.Pointer(C.goRendererInitialize)), shutdown_fn: (*[0]byte)(unsafe.Pointer(C.goRendererShutdown)), free_string: (*[0]byte)(unsafe.Pointer(C.goRendererFreeString)), free_user_data: (*[0]byte)(unsafe.Pointer(C.goRendererFreeUserData)), } // Call C registration cName := C.CString(impl.Name()) defer C.free(unsafe.Pointer(cName)) var cErr *C.char rc := C.kreuzberg_register_renderer( cName, vtable, unsafe.Pointer(uintptr(handle)), &cErr, ) if rc != 0 { msg := "failed to register Renderer" if cErr != nil { msg = C.GoString(cErr) C.kreuzberg_free_string(cErr) } handle.Delete() return fmt.Errorf("%s", msg) } // Store handle by name for later cleanup on unregister rendererRegistry.store(impl.Name(), handle) return nil } // UnregisterRenderer unregisters a Renderer implementation. func UnregisterRenderer(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) var cErr *C.char rc := C.kreuzberg_unregister_renderer(cName, &cErr) if rc != 0 { msg := "failed to unregister Renderer" if cErr != nil { msg = C.GoString(cErr) C.kreuzberg_free_string(cErr) } return fmt.Errorf("%s", msg) } // Delete the handle now that Rust has unregistered the plugin rendererRegistry.delete(name) return nil } // ClearRenderers removes all registered Renderer implementations. func ClearRenderers() error { var cErr *C.char rc := C.kreuzberg_clear_renderer(&cErr) if rc != 0 { msg := "failed to clear Renderer plugins" if cErr != nil { msg = C.GoString(cErr) C.free(unsafe.Pointer(cErr)) } return fmt.Errorf("%s", msg) } // Delete all handles now that Rust has cleared all plugins rendererRegistry.clear() return nil }