I’ve used a newtype struct for this before. I found it reasonably convenient – packing and unpacking the struct at the boundary of the BTreeSet/Map was only a small amount of boilerplate.
For the general newtype pattern, there are still a few inconveniences. A lot of them would be taken care of if we had an easy way to delegate trait impls to the contained type, and a zero-cost way to coerce containers of the newtype to containers of the original struct (and vice versa). There was another thread a month ago that discussed some of this: Revisit Orphan Rules