koicore FFI (Foreign Function Interface)
koicore provides a C-compatible Foreign Function Interface (FFI) that allows integration with C, C++, and other programming languages that can call C functions.
Overview
The koicore FFI module (koicore_ffi) exposes the core KoiLang parsing functionality through a C API. This enables applications written in C, C++, or other languages to parse KoiLang files and work with parsed commands.
Features
- C-compatible API: Full C API with C++ wrapper support
- Memory Management: Safe memory management with explicit ownership
- Comprehensive Coverage: Access to all core koicore functionality
- Error Handling: Detailed error reporting with position information
- Multiple Input Sources: Support for strings, files, and custom input sources
- Composite Parameters: Full support for lists and dictionaries
- Thread Safety: Designed for safe concurrent use
Building
Prerequisites
- Rust toolchain (stable)
- C++17 compatible compiler
- CMake 3.14 or later
- GoogleTest (automatically fetched by CMake)
Build Steps
# Build the Rust library
# Build and run C++ tests
Linking
Link against the compiled libkoicore_ffi.a (static library) or libkoicore_ffi.so (shared library):
# CMakeLists.txt
target_link_libraries(your_target koicore_ffi)
Quick Start
Basic Parsing Example
int
API Reference
Input Sources
String Input Source
KoiInputSource* ;
Creates an input source from a null-terminated C string.
Parameters:
source: UTF-8 encoded string to parse
Returns: Input source pointer or NULL on error
File Input Source
KoiInputSource* ;
KoiInputSource* ;
Creates an input source from a file with optional encoding specification.
Parameters:
path: File path (null-terminated)encoding: Character encoding (e.g., "utf-8", "gbk")encoding_strategy: How to handle encoding errors
Encoding Strategies:
Strict: Panic on invalid sequencesReplace: Replace with U+FFFD replacement characterIgnore: Skip invalid sequences
Custom Input Source
typedef struct KoiTextInputSourceVTable KoiTextInputSourceVTable;
KoiInputSource* ;
Create custom input sources by providing function pointers.
Input Source Cleanup
void ;
Frees input source memory.
Parser Configuration
typedef struct KoiParserConfig KoiParserConfig;
void ;
Initialize configuration with default values.
Parser Operations
KoiParser* ;
void ;
KoiCommand* ;
KoiParserError* ;
Create and use parser instances.
Command Operations
Command Creation
KoiCommand* ;
KoiCommand* ;
KoiCommand* ;
KoiCommand* ;
void ;
Create different types of commands.
Command Information
uintptr_t ;
uintptr_t ;
uintptr_t ;
int32_t ;
Get command metadata and parameter information.
Command Type Checking
int32_t ;
int32_t ;
int32_t ;
Check command type.
Parameter Access
int32_t ;
int32_t ;
uintptr_t ;
uintptr_t ;
Get parameter values by type.
Parameter Modification
int32_t ;
int32_t ;
int32_t ;
int32_t ;
int32_t ;
int32_t ;
int32_t ;
int32_t ;
Modify command parameters.
Composite Parameters
Lists
// Create list
KoiCompositeList* ;
void ;
// Get list from command
KoiCompositeList* ;
// List operations
uintptr_t ;
int32_t ;
// Add values
int32_t ;
int32_t ;
int32_t ;
// Get values
int32_t ;
int32_t ;
uintptr_t ;
uintptr_t ;
// Modify values
int32_t ;
int32_t ;
int32_t ;
// Remove values
int32_t ;
int32_t ;
Dictionaries
// Create dict
KoiCompositeDict* ;
void ;
// Get dict from command
KoiCompositeDict* ;
// Dict operations
uintptr_t ;
// Set values
int32_t ;
int32_t ;
int32_t ;
// Get values
int32_t ;
int32_t ;
uintptr_t ;
uintptr_t ;
// Get value type
int32_t ;
// Get keys by index
uintptr_t ;
uintptr_t ;
int32_t ;
// Remove entries
int32_t ;
int32_t ;
Error Handling
void ;
// Format error message
uintptr_t ;
uintptr_t ;
// Get error message only
uintptr_t ;
uintptr_t ;
// Get error position
int32_t ;
Advanced Examples
Working with Composite Lists
// Parse a command with a list parameter
KoiCommand* cmd = ;
if
;
Creating Commands with Composite Parameters
// Create a command with a list parameter
KoiCommand* cmd = ;
;
;
// Create and populate a list
KoiCompositeList* pos_list = ;
;
;
// Note: Adding composite parameters directly to commands
// requires additional API (not shown in basic example)
// Clean up
;
;
Error Handling Example
KoiCommand* cmd = ;
if
Custom Input Source Example
// Custom data structure
typedef struct CustomInputData;
// Custom next_line function
char*
// Custom source_name function
const char*
// Usage
const char* lines = ;
CustomInputData custom_data = ;
KoiTextInputSourceVTable vtable = ;
KoiInputSource* source = ;
// Use the source...
Memory Management
Ownership Rules
- Input Sources: Created with
KoiInputSource_From*functions, must be freed withKoiInputSource_Del - Parsers: Created with
KoiParser_New, must be freed withKoiParser_Del - Commands: Created with
KoiCommand_New*or returned from parser, must be freed withKoiCommand_Del - Composite Lists/Dicts: Created with
KoiComposite*_New, must be freed withKoiComposite*_Del - Errors: Created by parser, must be freed with
KoiParserError_Del
Lifetime Management
- Borrowed References: Composite lists/dicts obtained from commands are borrowed references owned by the command. Do not free them with
KoiComposite*_Del - Owned References: Composite lists/dicts created with
KoiComposite*_Newmust be explicitly freed - Transferred Ownership: When creating a parser with
KoiParser_New, ownership of the input source is transferred to the parser
Buffer Management
For string operations that require buffers:
- Call the
*_Lenfunction first to get the required buffer size - Allocate a buffer of the returned size (including null terminator)
- Call the actual function with the allocated buffer
- Remember to null-terminate the string if the function doesn't do it automatically
C++ Integration
For C++ users, koicore provides a namespace wrapper:
using namespace koicore;
// All C functions are available in the koicore namespace
KoiInputSource* source = ;
KoiParserConfig config;
;
Thread Safety
- Individual parser instances are not thread-safe
- Each thread should create its own parser instance
- Shared input sources can be used by multiple parsers if the source implementation is thread-safe
- Commands and composite parameters are immutable after creation and can be safely shared between threads
Error Codes
Most functions return integer status codes:
0: Success-1: Invalid parameters (NULL pointers, etc.)-2: Index out of bounds-3: Type mismatch-4: Invalid object state
String functions return the required buffer size when the provided buffer is insufficient.
Testing
The FFI module includes comprehensive tests using GoogleTest. Run all tests:
&&
Individual test executables:
test_parser: Basic parser functionalitytest_command: Command operationstest_composite_list: List parameter operationstest_composite_dict: Dictionary parameter operationstest_parser_error: Error handlingtest_input_source: Input source operations
Troubleshooting
Common Issues
- Linking Errors: Ensure you're linking against the correct koicore_ffi library
- Encoding Issues: Use
KoiInputSource_FromFileAndEncodingfor non-UTF-8 files - Buffer Overflows: Always check return values and allocate sufficient buffer space
- Memory Leaks: Follow ownership rules and use proper cleanup functions
- Thread Safety: Don't share parser instances between threads
Debug Tips
- Enable Rust debug symbols:
cargo build - Use sanitizers:
RUSTFLAGS="-Z sanitizer=address" cargo build - Check test output for usage examples
- Use error formatting to get detailed error messages
Performance Considerations
- Buffer Reuse: Reuse buffers for string operations to reduce allocations
- Batch Processing: Process multiple commands in batches when possible
- Memory Pools: Consider implementing memory pools for high-frequency usage
- Streaming: Use streaming parsers for large files to maintain constant memory usage
Version Compatibility
The FFI API maintains backward compatibility within major versions. When upgrading:
- Check the changelog for any breaking changes
- Rebuild your application with the new library
- Test thoroughly with your existing KoiLang files
Contributing
When contributing to the FFI:
- Maintain C compatibility
- Add comprehensive tests
- Update documentation
- Follow Rust FFI best practices
- Ensure thread safety where applicable