Only three ways to move the mouse seems relatively tame compared to the forest of Linux API calls when it comes to input (depends on X11/Wayland among other things). Also, your last link clearly states that the API call has been superseded, so if you follow the documentation you only have two options.
I don't think the difference between the two is all that strange. One sets the position of the cursor, the other interacts with the system like a normal mouse. The mouse and the cursor are separate things, and they're handled at different levels in the API stack, like XSendEvent and sending data to libinput.
I guess it depends on what level you're generating the events at. On Linux, it would be completely reasonable to inject the input events at the input device level.
This is very straightforward (EV_REL) and requires a very small amount of code. There can be different problems to deal with when working at this level, but in my experience, everything works as expected with keyboards, mice, and gamepads.
That's the thing, it really depends on what you're trying to accomplish. If you're trying to move the mouse as if some remote program was a mouse attached to your computer, generating inputs makes sense. If you provide some kind of remote support application that just needs to make the mouse appear at the place the remote tech indicates, changing the raw cursor makes sense.
Both approaches are reasonable and both are implemented in desktop operating systems for this reason.
I don't think the difference between the two is all that strange. One sets the position of the cursor, the other interacts with the system like a normal mouse. The mouse and the cursor are separate things, and they're handled at different levels in the API stack, like XSendEvent and sending data to libinput.