Writing C Library Wrapper That Ensures Safe Api Use


#1

Hi, I’m really interested in glfw-rs and vulkano and related graphics programming api’s, and so I’ve been experimenting with writing my own GLFW wrapper. One of the issues I’ve run into is how to tie objects created within a GLFW context to the GLFW context statically.
Firstly, just to explain a little bit, before you use GLFW, you must initialize the library with glfwInit() (i.e., create a GLFW context), and when you’re done, you should call glfwTerminate() to deinitialize the GLFW context (objects, resources, etc). Functions like glfwCreateWindow should only
be called while the GLFW context is alive, and the returned window should be tied to the lifetime of the context. My design thus far is like this: (error handling and function parameters removed in some places for clarity)

pub enum GLFWwindow {}
extern "C" {
    fn glfwInit();
    fn glfwTerminate();
    fn glfwCreateWindow() -> *mut GLFWwindow;
    fn glfwDestroyWindow(w: *mut GLFWwindow);
    fn glfwSetWindowTitle(w: *mut GLFWwindow, t: *const i8);
}
struct Context;
impl Context {
    fn new() -> Context {
        unsafe { glfwInit(); }
        return Context;
    }
    unsafe fn create_window(&self) -> *mut GLFWwindow {
        glfwCreateWindow()
    }
}
impl Drop for Context {
    fn drop(&mut self) {
        unsafe { glfwTerminate(); }
    }
}
struct Window<'a> {
    handle: *mut GLFWwindow,
    context: &'a Context,
}
impl Window {
    fn set_title(&mut self, title: &str) {
        let title = str_to_cstring_to_ptr(title);
        glfwSetWindowTitle(self.handle, title);
    }
}
impl Drop for Window {
    fn drop(&mut self) {
        unsafe { glfwDestroyWindow(self.handle); }
    }
}

I noticed that glfw-rs doesn’t give Windows references to the Context (note that glfw-rs's Context equivalent is Glfw), instead it makes the Context Copy and Clone, and then gives new objects clones of the context, which also makes it possible to define the methods of Context to take &mut self, which I believe makes more logical sense (you really shouldn’t be able to create a window if you only have an immutable reference to the Context, which is what my design allows), but by creating clones, you’re also not tying created objects to the context’s lifetime. Is there a way to make sure that windows are tied to the scope of the context that creates them, but also allow the context to be mutated after creating the window? Is there something else I’m completely misunderstanding or oblivious to? I’m also not an expert on GLFW by any means, is there any point to what I’m doing? I am in fact mostly trying to prevent usages of GLFW which never happen, but I’m still really curious about this sort of lifetime problem in general!