Note that we started our project before Rust was an option. These days I would certainly look at rust to see if that would cover our 5% of the needs but now we have a lot of C++ and mixing rust with C++ is a pain.
It is less pain than for most other languages, except for C. The pain is in exposing a C API for your C++ code. Then you build a library and you're set - because basically every language has the ability to call C code. Python, Rust, Java, etc. etc.
The painful part is to have to go through a C API (modern languages can express much richer APIs and of course there are different constraints on the different runtimes, e.g. GC).
The annoying part is that each language adds overhead (its runtime). I wouldn't call it painful (I don't have much to do about it), I say "annoying" just because I would rather minimise the amount of code I ship.
Pointers - better null check them even if you guarantee they won't be null. (assuming they are supported at all in the target, if not copy all the data in out)
Want to use a string - your language probably has a better string type the null terminated C string - are you going to pay the overhead to copy the string (remember to copy it back and forth for each call); or are you going to use C strings in your non-C code? Don't forget to remember the length of the buffer is different from the length of the string if you modify that string.
What to use a list - C supports arrays (which are just syntactic pointers). Nearly ever language has a better list type, which for starters encodes length.
Many languages are garbage collected, which is going to require a lot of work to make work well across the C API.
And so on.
For the above, as a C++ programmer I'm reaching for std::string and std::vector - which are both very good. I have a much better type than the C API allows, but I can't use it. Odds are your language has an equivalent that is just as good (possibly with different trade offs - those details are not the point so lets not argue it here), but since the memory layout isn't 100% the same you can't use my string/vectors directly in code as if they are the native types.
On the surface it seems easy. If you are only doing it a few times it isn't hard. However the details are hard and important and the more you mix the harder it gets since the above details (any many many more on the same lines) start to matter.
I agree that the more you mix, the harder it gets. Maybe I'm just never working on "serious" projects, but I have never been in a situation where I had to mix 10 languages.
Similarly I like to do video stuff in C just because I call gstreamer/ffmpeg directly in C, rather than having to bridge everything.