Cargo feature or separate crate?

My aurum-window library is a general purpose window management library which is not intended to favor any rendering API (OpenGL, Direct3D, Cairo, etc.) over another. At the moment it only supports OpenGL for rendering, but I intend to add support for others. I have tried two approaches which each have their own drawbacks:

  1. Add OpenGL support through a cargo feature. This is how it is currently implemented, but I'm not happy with the number of occurrences of #[cfg(feature="opengl")] throughout the library. Also, adding support for more rendering libraries will make the crate grow, but this may not be much of a problem, as it is pretty small on its own. I'm mostly concerned about the cfgs everywhere.

  2. Add OpenGL support from another crate (probably called aurum-gl-window). This is how it used to be implemented, but I have since changed it to the first choice listed. The main drawback here is that it requires that I expose a lot of aurum-window's internals. And I do mean a lot. For example, creating a GLX window as opposed to a window with Xlib GC rendering requires that a unique colormap is specified (exposing a Colormap wrapper struct), and that a special X11 visual is provided after being selected with glXChooseFBConfig (exposing a Visual wrapper struct). Exposing these internal types would allow the user of the library to potentially mess things up, but mostly only within unsafe blocks.

I'm having trouble weighing the pros and cons to each approach, but I'm somewhat leaning toward going back to choice 2. Any suggestions would be appreciated!

1 Like

Maybe you could find some low-medium API layer where drawing backend specifics are abstracted enough, and then implement main logic in terms of those primitive operations.