Yeah it's pretty out of date. You might then "eh that doesn't matter, I like things to be stable and I'll just imagine I'm three years in the past".
That works until some software introduces a bug fix or a new feature that you really need and you can't use it because of your distro's weird update policies.
You will very quickly find that you don't care anywhere near as much about theoretical stability as you do about a concrete feature or bugfix that is available but inaccessible.
I say theoretical because in practice Debian stable isn't really much more stable than more up-to-date distros. It just has fewer new bugs and more old bugs.
They might try to claim they backport fixes for the old bugs, but in reality they don't have the manpower to do that for 100k packages or whatever it is. They do it for critical bugs of very important packages but that's it.
Right... I mean the idea is obvious so why even bother with any of it? The only interesting reason is to demo that it actually works in reality which clearly they didn't.
My advice is that you debug via tests. If you install Rust-analyzer (you probably already have) then any tests you add have a little "Run test" and "Debug test" button next to them that you can just click. It magically works without having to faff around with JSON files.
As for your current setup, as other said you have an issue in Cargo.toml which is unrelated to debugging, and the target binary is in target/debug, not in the workspace root.
One of the things I hate about merge-based Git workflows is git makes a default Merge 123234234 from user/dave/fsdf message which:
a) Is shit - it contains zero useful information (what's in the change??) and contains information you explicitly don't care about (the temporary branch name the author happened to use).
a) Makes people think they are supposed to use that message.
It would probably be better if the default message was blank. But also squash & rebase is generally better anyway and it avoids this problem entirely.
Its definitely best to try and avoid raw pointers, but even if you try really hard I found it's not really possible to get a Rust-like experience with no UB.
Even something as simple as std::optional - you can easily forget to check it has a value and then boom, UB.
The C++ committee still have the attitude that programmers are capable of avoiding UB if they simply document it, and therefore they can omit all sanity checks. std::optional could easily have thrown an exception rather than UB but they think programmers are perfect and will never make that mistake. There are similar wild decisions with more recent features like coroutines.
They somehow haven't even learnt the very old lesson "safe by default".
If I wanted memory unsafety I think I would consider Zig instead of C++ at this point.
Rust for now, by a wide margin. But I'm following other languages that I think have the potential to surpass it, including Vale (promises way more than it delivers currently), Koka, Hylo, maybe Lobster.
Fresh is the best way to make websites, and Deno is the best way to write infrastructure scripts IMO. I really hope they don't run out of money.