title: Creating a rust shared library that returns a struct of function pointers to C main program
body: <p>I'm trying to make a Rust binding to nbdkit without much luck.  I need to make a <code>.so</code> file, which is easy.  The <code>.so</code> file must have a public function called <code>plugin_init</code>, also easy.  However this function must return a pointer to a C-compatible <code>struct</code> containing a mix of strings and function pointers (that the C main program will later call).</p>
  
  <p>The API is: <a href="https://github.com/libguestfs/nbdkit/blob/409ce4c9238a84ede6688423b20d5f706067834b/include/nbdkit-plugin.h#L53" rel="nofollow noreferrer">https://github.com/libguestfs/nbdkit/blob/409ce4c9238a84ede6688423b20d5f706067834b/include/nbdkit-plugin.h#L53</a></p>
  
  <p>I came up with:</p>
  
  <pre><code>#[repr(C)]
  pub struct NBDKitPlugin {
      _struct_size: uint64_t,
      _api_version: c_int,
      _thread_model: c_int,
  
      name: *const c_char,
      longname: Option&lt;*const c_char&gt;,
      version: Option&lt;*const c_char&gt;,
      description: Option&lt;*const c_char&gt;,
  
      load: Option&lt;extern fn ()&gt;,
      unload: Option&lt;extern fn ()&gt;,
  
      config: Option&lt;extern fn ()&gt;, // XXX
      config_complete: Option&lt;extern fn () -&gt; c_int&gt;,
      config_help: Option&lt;*const c_char&gt;,
  
      open: extern fn (c_int) -&gt; *mut c_void,
      close: Option&lt;extern fn (*mut c_void)&gt;,
  }
  </code></pre>
  
  <p>and a <code>plugin_init</code> function:</p>
  
  <pre><code>extern fn hello_load () {
      println! ("hello this is the load method");
  }
  
  struct MyHandle {
  }
  
  extern fn hello_open (readonly: c_int) -&gt; *mut c_void {
      println! ("hello, this is the open method");
      let mut h = MyHandle {};
      let vp: *mut c_void = &amp;mut h as *mut _ as *mut c_void;
      return vp;
  }
  
  #[no_mangle]
  pub extern fn plugin_init () -&gt; *const NBDKitPlugin {
      println! ("hello from the plugin");
  
      let plugin = Box::new (NBDKitPlugin {
          _struct_size: mem::size_of::&lt;NBDKitPlugin&gt;() as uint64_t,
          _api_version: 2,
          _thread_model: 3,
          name: CString::new("hello").unwrap().into_raw(),
          longname: None,
          version: None,
          description: None,
          load: Some (hello_load),
          unload: None,
          config: None,
          config_complete: None,
          config_help: Some (CString::new("my config_help here").unwrap().into_raw()),
          open: hello_open,
          close: None,
      });
  
      return Box::into_raw(plugin);
  }
  </code></pre>
  
  <p>Apart from leaking memory, this partially works.  The integers and strings are seen from C OK.  However the function pointers don't work at all.  They are completely bogus and seem to occupy more space than a raw pointer so I suppose that I'm exposing a "fat" Rust pointer.</p>
  
  <p>There seems very little documentation on this topic that I can find.  Help.</p>