The closest you can do is to abstract the entire reference type away, i.e. use a generic non-borrowed T that users of your code can substitute for &mut U or &U as they wish.
However, you will quickly run into limits of this approach, and Rust just doesn't have any good answer to this. Separate _mut versions are the norm. The borrowing rules for shared and exclusive references are quite different, and there's no feature directly unifying them.
Macro can be a good solution Or you can try to call shared/immutable helper functions from the mutable/exclusive version of the function, since you can borrow &mut as &, but not the other way.