Can I avoid recompiling my platform layer without `static mut`? [duplicate] - static

This question already has answers here:
How do I create a global, mutable singleton?
(7 answers)
How can you make a safe static singleton in Rust?
(3 answers)
Closed 3 years ago.
I have a library "business logic" crate I want to be able to write multiple binary crate "frontends" or "platform layers" for. These platform layers tend to use libraries calling platform APIs and that tends to imply long compile times. I want to be able to iterate on the business logic crate without needing to recompile the platform layer. But, I want to be able to compile the project into a single binary for each platform, and I'd rather not mess with shared object files/DLLs if I don't have to.
I have a way to do this using a fn pointer and static mut, but there's this rust-lang/rust issue about potentially removing it, so I'd like to know if there is a way to get the results I want without using it.
For reference, the way I got it working was like this:
use platform_types::{Input, Output};
fn update_and_render(input: Input) -> Output {
static mut STATE: logic::State = logic::new();
let state: &mut logic::State = unsafe { &mut STATE };
logic::update_and_render(state, input)
}
fn main() {
platform_layer::run(update_and_render);
}
where the above code is in the main crate, logic is the business logic crate, platform_layer is the platform layer crate, and platform_types contains the common types between the three other crates.
I tried using a RefCell with try_borrow_mut I got the error std::cell::RefCell<State> cannot be shared between threads safely and mentions that Sync is not implemented for std::cell::RefCell<State> and the error did not go away if I tried implementing Sync for State experimentally. I then tried a Mutex, but as far as I can tell I can't put one in a static.
EDIT: If it makes a difference, I don't actually expect to need to call the function pointer from multiple threads, although I understand that handing one out implicitly allows that. If I ever (accidentally?) do call the function pointer from multiple threads, a failed debug_assert! or similar is obviously preferable to UB.

You can use a static mutex and get a local mutable reference when needed:
#[macro_use]
extern crate lazy_static;
use std::sync::Mutex;
fn update_and_render(input: Input) -> Output {
lazy_static! {
static ref STATE_MUTEX: Mutex<logic::State> = Mutex::new(logic::new());
}
let mut state = STATE_MUTEX.lock().unwrap();
logic::update_and_render(state, input)
}
This is fast, safe, and ready for access from multiple threads.

You can move state to main()
fn main() {
let mut state = logic::new();
platform_layer::run(move |input| logic::update_and_render(&mut state, input));
}

Related

Enforce function isolation at compile time

I am working on a project in C Visual Studio, and I have two sets of functions, let’s call them SET_1 and SET_2.
I wonder if there is a way to ensure that a function from SET_1 calls only functions from SET_1 and not functions from SET_2.
The simplest solution will be to split the project in 2, but I want to avoid any major refactoring. I probably can make some runtime checks but I want to avoid this too…
So, I am wondering if there is something like SAL annotations that I can use to enforce this isolation at compile time?
Here is an example of what I want:
#define SET_1 ...
#define SET_2 ...
SET_1
void Fct1()
{
// ...
}
SET_1
void Fct2()
{
Fct1(); // Ok, both functions have SET_1 tag
}
SET_2
void Fct3()
{
Fct1(); // Compile error, Fct1 has a different tag
}
I don’t want to write some kind of code parser to manually enforce this rule.
I have multiple files and a file contains functions from both sets. The functions don’t have any common characteristic, I manually need to specify the set for each function.
The solution can be at compile time or at build time. I just want to make sure that a function from set1 will not be called from set2
I can modify the code and I know that the right solution will be to refactor the project, but I am curious if there is another solution.
For example, if the code was in C++, I could include all functions from set1 inside a namespace and those from set2 inside another namespace. But this will not work if we have a class with function members in different sets.

Shared pointer in rust arrays

I have two arrays:
struct Data {
all_objects: Vec<Rc<dyn Drawable>>;
selected_objects: Vec<Rc<dyn Drawable>>;
}
selected_objects is guarenteed to be a subset of all_objects. I want to be able to somehow be able to add or remove mutable references to selected objects.
I can add the objects easily enough to selected_objects:
Rc::get_mut(selected_object).unwrap().select(true);
self.selected_objects.push(selected_object.clone());
However, if I later try:
for obj in self.selected_objects.iter_mut() {
Rc::get_mut(obj).unwrap().select(false);
}
This gives a runtime error, which matches the documentation for get_mut: "Returns None otherwise, because it is not safe to mutate a shared value."
However, I really want to be able to access and call arbitrary methods on both arrays, so I can efficiently perform operations on the selection, while also being able to still perform operations for all objects.
It seems Rc does not support this, it seems RefMut is missing a Clone() that alows me to put it into multiple arrays, plus not actually supporting dyn types. Box is also missing a Clone(). So my question is, how do you store writable pointers in multiple arrays? Is there another type of smart pointer for this purpose? Do I need to nest them? Is there some other data structure more suitable? Is there a way to give up the writable reference?
Ok, it took me a bit of trial and error, but I have a ugly solution:
struct Data {
all_objects: Vec<Rc<RefCell<dyn Drawable>>>;
selected_objects: Vec<Rc<RefCell<dyn Drawable>>>;
}
The Rc allows you to store multiple references to an object. RefCell makes these references mutable. Now the only thing I have to do is call .borrow() every time I use a object.
While this seems to work and be reasonably versitle, I'm still open for cleaner solutions.

How to pass GoLang's struct's method as C callback

In Go source I have
type T struct {
// some data
}
func (t *T)M(arg0 SomeType1) {
// some computations
}
var Obj *T
In C sources I have
// SomeType1C is equivalent to SomeType1.
typedef void (*CallbackFunc)(SomeType1C);
// callback will be called !after! register_callback function returns.
void register_callback(CallbackFunc callback);
I would like to use Obj.M as callback for register_callback in C.
On MS Windows for winapi I pass smth like C.CallbackFunc(unsafe.Pointer(syscall.NewCallback(Obj.M))) to register_callback for this (not sure is it fully correct, but at least this works). But where is no NewCallback for non-Windows systems.
PS:
I'm sure that callback is registered after T is initialised and removed before T is removed.
I may have multiple instances of T and some of them may be used to callback's 'source' at same time (so T is not some kind of singltone).
Function pointer callbacks in GoLang's wiki uses gateway function, but I don't see how to adequate use it with struct's method.
Base idea:
Use exported callback as a proxy between C and Go:
//export callback
func callback(data0 SomeType1C, data1 Data){ // data1 - data passed to register_callback_with_data
obj := convertDataToObj(data1)
obj.M(data0)
}
and register it like this:
register_callback_with_data(callback, convertObjToData(obj));
Where are 3 ways: wrong (and easy), limited (medium) and right (hard).
Wrong (and easy) way:
Pass pointer to Go struct into C (as in original answer). This is totally wrong because Go runtime can move struct in memory. Usually this operation is transparent (all Go pointers will be updated automatically). But pointers in C memory to this struct will not be updated and program may crash/UB/... when tries to use it. Do not use this way.
Limited (medium) way:
Similar to previous, but with Go struct allocated in C memory:
Obj = (*T)(C.calloc(C.size_t(unsafe.Sizeof(T{}))))
In this case Obj can not be moved by Go runtime because it is in C memory. But now if Obj has pointers to Go memory (fields with *-variables, maps, slices, channels, function-pointers, ...) then this also may cause crash/UB/... This is because:
if there are no (other) Go pointers to the same variable (memory), then Go runtime thinks that this memory is free and can be reused,
or, if there is other Go pointer to same variable (memory), then Go can move this variable in memory.
So, use this way only if struct has no pointers to Go memory. Usually this means that struct contains only primitive fields (ints, floats, bool).
Right (and hard) way:
Assign id (of integer type for example) for each object of type T and pass this id into C. In exported callback you should convert id back to object. This is right way with no limitation, so this way may be used always. But this way requires to maintain some array/slice/map to convert between objects and ids. Moreover, this convertation may require some synchronization for thread-safe (so see sync.Mutex and sync.RWMutex).
Original answer:
Not best answer and has restrictions, but no other suggested. In my case I can pass additional data to register_callback. This data will be passed back to callback on each call. So I pass unsafe.Pointer(Obj) as data and use gateway function:
//export callback
func callback(data SomeType1C, additionalData unsafe.Pointer){
obj := (*T)(additionalData) // Get original Obj (pointer to instance of T)
dataGo := *(*SomeType1)(unsafe.Pointer(&data)) // Cast data from C to Go type
obj.M(dataGo)
}
and register it like this:
register_callback_with_data(callback, unsafe.Pointer(Obj));
PS: but still want to know how to do this better in general case (without additional data).

How do I provide access to the library I wrap with cgo?

I am trying to write bindings for a C library, specifically the libnfc. My current code is available on Github.
One of the central structures in the libnfc is the device. It is represented by the Go type Device.
type Device struct {
d *C.nfc_device
}
All functions inside the libnfc that operate on a Device are methods of it. Now, there are other C libraries (e.g. the libfreefare) whose APIs operates on nfc_devicees. For the sake of modularity, I want to place the code for each library I wrap into its own module. This leads to the problem, that I can't access private structure members from within other modules. I thought about the following solutions:
Make d a public member of Device
This would make it easy to access the underlying nfc_device from within other modules, but it makes it also easy to sidestep type safety. Additionally, I don't know whether cgo recognizes pointers to foreign types if they come from different modules. Finally, I lose flexibility if I change the structure of the Device type.
Add an accessor func (Device) GetCPtr() unsafe.Pointer
This solves the issues above but introduces the new issue that you suddently have access to an unsafe.Pointer in a module that might not even import unsafe.
Add an accessor func (Device) GetCPtr() uintptr
This solves the aforementioned issue, as you have to manually cast the result to get a proper pointer.
Are there any ways I missed? Is there a better, more idiomatic way to provide access to the underlying nfc_device?
I'm generally in favour with the third proposal of yours as this is the way the reflect package
handles this issue.
What you could also do is to expose only an interface in your libnfc wrapper, e.g.
type NFCDevice interface {
Read() ([]byte, error)
Write() ([]byte, error)
// ...
}
Now you have a public API that is safe.
Additionally, your device type implements a function
func (d *device) NfcDevice() *C.nfc_device {
return d.nfc_device
}
which you can use in your other wrappers by asserting your NFCDevice to implement the
interface
interface {
NfcDevice() *C.nfc_device
}
which you can create on the fly in the other wrappers. This way a programmer has to deliberately
do something to access the inner workings of your device.

How can I allocate and re-use a C struct from Haskell?

In particular, I'm trying to learn Haskell's foreign function interface by writing a binding to the Allegro game library. In Allegro's native C, the main event loop looks something like this:
// initialize event struct
ALLEGRO_EVENT event;
// main loop
while (running) {
if (al_get_next_event(event_queue, &event)) {
// process event here ...
}
}
Using ghc and hsc2hs, I can write a foreign function call like:
foreign import ccall "allegro5/allegro.h al_get_next_event"
alGetNextEvent :: EventQueue -> Ptr (Event) -> IO (CInt)
where EventQueue is a pointer to an opaque structure and Event is a Storable instance based off of C's ALLEGRO_EVENT.
Ideally, for the user-facing Haskell function, I would like to have a type signature like
getNextEvent :: EventQueue -> Maybe Event
which would abstract away initializing the ALLEGRO_EVENT struct and boolean return value.
My question is, how should I write this function to maximize memory efficiency? I could malloc a new pointer to Event inside the method and use that, but since I'm working with C-based data, I want to make sure I'm re-using existing space and not constantly allocating new structs. I also want to avoid having the user malloc the struct and pass it in to every call.
Any advice?
Typically, if it is locally scoped data, you would use
alloca
If the data has longer scope,
mallocForeignPtr
is a good choice, since it is very fast, you can attach finalizers, and you don't have to clean up on your own.
The GHC runtime takes care of maximally reusing space for you, so there's not too much of a need to worry about efficiency by e.g. pinning a mutable memory buffer in place. Just let the GC take care of things.

Resources