Expand description
§Minimal Unsafe C API for OpenMP Parser
This module provides a direct pointer-based C FFI with minimal unsafe code.
§Design Philosophy: Direct Pointers vs Handles
We use raw C pointers to Rust structs instead of opaque handles for:
- Idiomatic C API: Standard malloc/free pattern familiar to C programmers
- Simple memory model: No global registry, no handle bookkeeping
- Easy integration: Works naturally with C/C++ code
- Minimal code: 632 lines vs 4000+ lines of handle management
§Safety Analysis: 18 Unsafe Blocks (~60 lines)
All unsafe blocks are:
- NULL-checked before dereferencing
- Documented with explicit safety requirements
- Isolated only at FFI boundary, never in business logic
- Auditable: ~0.9% of file (60 unsafe lines / 632 total)
§Case-Insensitive Matching: String Allocation Tradeoff
Functions directive_name_to_kind()
and convert_clause()
allocate a String
for case-insensitive matching (Fortran uses uppercase, C uses lowercase).
Why not optimize with eq_ignore_ascii_case()
?
- Constants generator (
src/constants_gen.rs
) requiresmatch
expressions - Parser uses syn crate to extract directive/clause mappings from AST
- Cannot parse if-else chains → must use
match normalized_name.as_str()
- String allocation is necessary for match arm patterns
Is this a performance issue?
- No: These functions are called once per directive/clause at API boundary
- Typical usage: Parse a few dozen directives in an entire program
- String allocation cost is negligible compared to parsing overhead
Future optimization path: Update constants_gen.rs
to parse if-else chains,
then use eq_ignore_ascii_case()
without allocations.
§Learning Rust: Why Unsafe is Needed at FFI Boundary
- C strings → Rust strings:
CStr::from_ptr()
requires unsafe - Memory ownership transfer:
Box::into_raw()
/Box::from_raw()
- Raw pointer dereferencing: C passes pointers, we must dereference
Safe Rust cannot verify C’s guarantees, so we explicitly document them.
§C Caller Responsibilities
C callers MUST:
- ✅ Check for NULL returns before use
- ✅ Call
_free()
functions to prevent memory leaks - ✅ Never use pointers after calling
_free()
- ✅ Pass only valid null-terminated strings
- ✅ Not modify strings returned by this API
Structs§
- OmpClause
- Opaque clause type (C-compatible)
- OmpClause
Iterator - Iterator over clauses
- OmpDirective
- Opaque directive type (C-compatible)
- OmpString
List - List of strings (for variable names in clauses)
Constants§
- ROUP_
LANG_ C - C language (default) - uses #pragma omp
- ROUP_
LANG_ FORTRAN_ FIXED - Fortran fixed-form - uses !$OMP or C$OMP in columns 1-6
- ROUP_
LANG_ FORTRAN_ FREE - Fortran free-form - uses !$OMP sentinel
Functions§
- roup_
clause_ default_ data_ sharing - Get default data sharing from default clause.
- roup_
clause_ free - Free a clause.
- roup_
clause_ iterator_ free - Free clause iterator.
- roup_
clause_ iterator_ next - Get next clause from iterator.
- roup_
clause_ kind - Get clause kind.
- roup_
clause_ reduction_ operator - Get reduction operator from reduction clause.
- roup_
clause_ schedule_ kind - Get schedule kind from schedule clause.
- roup_
clause_ variables - Get variable list from clause (private, shared, reduction, etc.).
- roup_
directive_ clause_ count - Get number of clauses in a directive.
- roup_
directive_ clauses_ iter - Create an iterator over directive clauses.
- roup_
directive_ free - Free a directive allocated by
roup_parse()
. - roup_
directive_ kind - Get directive kind.
- roup_
parse - Parse an OpenMP directive from a C string.
- roup_
parse_ with_ language - Parse an OpenMP directive with explicit language specification.
- roup_
string_ list_ free - Free string list.
- roup_
string_ list_ get - Get string at index from list.
- roup_
string_ list_ len - Get length of string list.