-
Notifications
You must be signed in to change notification settings - Fork 6
Design decisions
The Ωedit™ library is designed as a C library, though the C API can be implemented in C and/or C++, what is publicly exposed is a C API. As a free, open-source library, Ωedit is designed to be portable and easily integrated into other products, and a simple C API is a reasonable way to accomplish those objectives.
While Ωedit™ is a C library, it does allow for C++ conveniences, but the core public API must be in C, with optional C++ conveniences. All core functionality will be in C .h
headers and C++ conveniences will be in C++ .hpp
headers making them easily distinguishable from one another based on the file extension.
The Ωedit™ library does not publicly expose its data structures, only functions that act on opaque pointers. This gives the library complete control over its internal data structures and how they are accessed and mutated.
Ωedit™ uses int64_t
, 64-bit signed integers, for offsets and lengths instead of unsigned counterparts like off_t
, size_t
, and uint64_t
. This is done to maximize portability, integration possibilities, and to provide error reporting using negative values. This means the maximum length and offset that Ωedit can handle is 18,446,744,073,709,551,616, instead of twice that, which is acceptable.
The core Ωedit™ library is not thread-safe. Thread safety is done in middleware or the application layer.
As a relatively simple C API, we want it to be accessible to different programming languages. Ωedit uses C callbacks to handle events. Callbacks can be a significant challenge as there is no standard way for C code to call functions written in other languages. We tried using SWIG to generate bindings, but couldn't get clean callback support, so we decided to use jnr-ffi
and hand-write the bindings instead of using a generator like SWIG. The resulting code is much cleaner and understandable over hundreds of lines of generated code and questionable (at best) support for callbacks.
Ωedit™ has a very efficient Remote Procedure Call (RPC) implementation for a server and client. The RPC middleware handles threaded event subscription streams. We selected gRPC as our RPC solution because it's fast, relatively safe (using protocol buffers for data transfer objects (DTO)), uses a simple RPC definition language, generates server and client boilerplate in a large number of modern languages, works bidirectionally over HTTP/2 or Unix Domain Sockets (UDS), is cross-platform, and Apache 2 licensed (FOSS).