You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a WIP for outlining the patterns to be followed for creating the C FFI. The content in this issue will be edited and evolve into the actual top level overview documentation for the C API. I don't have a lot of experience with good C APIs, so ideas are welcome.
Error Handling
All functions that can error return an i32 error code
If the function is successful then 0 is returned (no error)
If the function fails in a way that is caught explicitly then a specific positive error code associated with that function is returned (e.g. maybe 1 for null input), these specific error codes are documented
All panic unwinds are caught, if an unwind occurred then -1 is returned, these represent an "internal algorithm error" type of bug
All functions return values via output parameters as pointers (return value is always reserved for error code, parameters are documented as such)
After an error occurs an error message string and error report string are set and stored in thread local storage
cavc_last_error_msg and cavc_last_error_report can be used to retrieve the last error message and last error report as char* read only null terminated c strings, due to the thread local storage it must be accessed from the same thread which called the function that had an error (char* pointer will be invalid after next error occurs)
The error message is a human readable error message, the error report may hold serialized data with the name of the function and the inputs given for use in reproducing the issue
If the error message or error report is not set then a valid null terminated empty c string is returned
Naming and Type Conventions
All symbols (structs and functions) start with cavc_ for namespacing.
f64 (double in C) is used as the numeric type.
u8 (unsigned char in C) is used as a logical boolean (0 is false, otherwise true).
Conventional null terminated char* c strings are used for strings
Object creation functions end with the word create, e.g. cavc_pline_create.
Memory free functions end with _f, e.g. cavc_pline_f.
Property/data assessor functions use the word get, e.g. cavc_pline_get_is_closed.
Property/data setter functions use th workd set, e.g. cavc_pline_set_is_closed.
Computed value functions use eval or find, e.g. cavc_pline_eval_area.
Option Structs
There is a need to support option parameters for more complex functions. There could be an option struct associated with each function that supports optional parameters, for example:
The cavc_pline_eval_offset could have a cavc_pline_eval_offset_o struct as one of the parameters. The cavc_pline_eval_offset_o struct could hold epsilon values and other parameters to be used by the offset algorithm and could look something like this:
There could then also be a cavc_pline_eval_offset_o_i function that accepts a *mut cavc_pline_eval_offset_o for initializing sensible defaults.
The issue with this is API stability if we want to add new fields to the option struct in the future. Even if all the functions take the option struct by reference/pointer the functions wont know if a newer field is present or not. And this is really bad considering everything may "seem to work" when in fact the library is reading past the end of the struct memory because the calling side is assuming a different set of fields in the struct.
One solution is to make the option struct opaque and have the construction of the struct and all fields be modified through functions but this has several downsides: a create and free function must be created for the type and memory allocation managed by the caller, all fields must have a get/set function associated with them, and from a performance perspective heap memory allocations and frees must be performed around managing the option parameters (which could be very frequent).
Another solution is to not attempt to make the option structs be forward compatible and just create a new function and new struct type if new options are added (while keeping the old function and struct the same for continued compatibility), e.g. cavc_pline_eval_offset2 and cavc_pline_eval_offset_o2.
Current plan is to follow the pattern of just creating a new function and option struct, leaving the previous version present to not break backward compatibility. However this would all be done after a 1.0 release, before then there may be some breaking changes in iteration to arrive at a 1.0 API and ideally no second version functions are required. It may also be that there is just a 2.0 release if enough changes pile up of this nature.
The text was updated successfully, but these errors were encountered:
This is a WIP for outlining the patterns to be followed for creating the C FFI. The content in this issue will be edited and evolve into the actual top level overview documentation for the C API. I don't have a lot of experience with good C APIs, so ideas are welcome.
Error Handling
i32
error code0
is returned (no error)1
for null input), these specific error codes are documented-1
is returned, these represent an "internal algorithm error" type of bugcavc_last_error_msg
andcavc_last_error_report
can be used to retrieve the last error message and last error report aschar*
read only null terminated c strings, due to the thread local storage it must be accessed from the same thread which called the function that had an error (char*
pointer will be invalid after next error occurs)Naming and Type Conventions
cavc_
for namespacing.f64
(double
in C) is used as the numeric type.u8
(unsigned char
in C) is used as a logical boolean (0
is false, otherwise true).char*
c strings are used for stringscreate
, e.g.cavc_pline_create
._f
, e.g.cavc_pline_f
.get
, e.g.cavc_pline_get_is_closed
.set
, e.g.cavc_pline_set_is_closed
.eval
orfind
, e.g.cavc_pline_eval_area
.Option Structs
There is a need to support option parameters for more complex functions. There could be an option struct associated with each function that supports optional parameters, for example:
The
cavc_pline_eval_offset
could have acavc_pline_eval_offset_o
struct as one of the parameters. Thecavc_pline_eval_offset_o
struct could hold epsilon values and other parameters to be used by the offset algorithm and could look something like this:There could then also be a
cavc_pline_eval_offset_o_i
function that accepts a*mut cavc_pline_eval_offset_o
for initializing sensible defaults.The issue with this is API stability if we want to add new fields to the option struct in the future. Even if all the functions take the option struct by reference/pointer the functions wont know if a newer field is present or not. And this is really bad considering everything may "seem to work" when in fact the library is reading past the end of the struct memory because the calling side is assuming a different set of fields in the struct.
One solution is to make the option struct opaque and have the construction of the struct and all fields be modified through functions but this has several downsides: a create and free function must be created for the type and memory allocation managed by the caller, all fields must have a get/set function associated with them, and from a performance perspective heap memory allocations and frees must be performed around managing the option parameters (which could be very frequent).
Another solution is to not attempt to make the option structs be forward compatible and just create a new function and new struct type if new options are added (while keeping the old function and struct the same for continued compatibility), e.g.
cavc_pline_eval_offset2
andcavc_pline_eval_offset_o2
.Current plan is to follow the pattern of just creating a new function and option struct, leaving the previous version present to not break backward compatibility. However this would all be done after a 1.0 release, before then there may be some breaking changes in iteration to arrive at a 1.0 API and ideally no second version functions are required. It may also be that there is just a 2.0 release if enough changes pile up of this nature.
The text was updated successfully, but these errors were encountered: