Naming convention for modules that talk to other crates

In my work on all-is-cubes, I often find that I need to translate between types I have defined and types in an existing library crate. For example, graphics/mathematical types like Vec3 or colors, or user input events. These translations may be straightforward From implementations, but quite frequently have to be named functions.

I find it useful to place such conversions or other “glue code” in a module of its own, so as to not clutter the application logic with mostly-boilerplate and to have a predictable place to find it. However, I have not found any really satisfactory way of naming that module — taking into consideration that it would be confusing, and occasionally actually conflicting, to have an imported name equal to the crate that isn't the crate.

Suppose that library foo is not mine, and library bar is mine and depends on foo. I have found myself at different times using several different ways of naming the glue module:

  • bar::in_foo
  • bar::foo_support
  • bar::glue::foo
  • bar::foo::glue (when foo is literally the name of the topic as well as the library I am using, e.g. gltf)

(Note that in most of these cases, the glue module is not public; I'm giving paths as if they were public just for the “big picture”.)

Any suggestions for an even better module layout, or which kind of naming is clearer or more aligned with existing practice? I'm not facing any practical problem stopping me from making progress here, but it would be nice to be consistent and not forever in doubt about what is best.

1 Like

Some time ago I used to use insulation but that's too much typing. Maybe insulator?

I still use veneer. My preference is a flatter structure...

  • bar::foo_veneer

My coworkers have never complained so that must not be too troublesome. Ironically, it is a bit problematic for me. I tend to confuse "facade", the design pattern, with "veneer". I've even accidentally named classes WhateverVeneer.

Note that the cases I am concerned with are not primarily about making a complete wrapper around foo's API surface, only individual conversions/helpers. (The complete wrappers, when they exist, may or may not end up there too.)

Also, it would be nice if the naming style works well with the import style where you use the module rather than the items in it — which means a short name for the module is better. Of course, renaming is possible; for example, when I found myself writing foo_support, I could use that as use crate::foo_support as fs;. But a name that does not need abbreviation, or has an obvious one, is better.

how about

pub(crate) mod foo {
    /// optional re-export names of foo
    pub use ::foo::*;
    pub mod interop {
        use ::foo as foreign;
        impl From<foreign::FooType> for crate::MyBar {
            fn from(value: foregin::FooType) -> crate::MyBar {
                todo!()
            }
        }
        pub fn from<T: foreign::FooTrait> for crate::MyBar {
            todo!()
        }
    }
}
#[test]
fn test_foo_interop() {
    let bar = foo::interop::from(foo::create_foo(42));
    assert!(bar.contains(42));
}

I feel it would be confusing to have a module

  • named identical to the foo crate name, and
  • with contents that are identical except for one added item;

it might send readers of my code looking for that added item in the original foo's documentation. One or the other might be a component of a good solution, but both is too much.

For the case where

  • the extent of glue to the external crate is trait impls, and
  • the use of the crate within the parent module is limited to the glue module(s),

(e.g. serde trait impls for an optional serde dependency, and where none are purely derived) I tend to just name the module after the crate[1].

I've not had to make extensive glue where other modules want to access the concrete types involved, but my first instinct would be to use glue::* for a single crate or glue::crate::* for multiple crates, and potentially pub useing some self::crate::* names in mod glue which are unambiguously named.


  1. Well, actually, I'll more often have two mod ser and de, since manual serde impls take up some significant space and that pattern works when the containing module wants to import the derives as well. ↩︎

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.