I commented the section of the code where I'm having problems. It's a little long to paste here.
So as you can see calling d.print() causes Dog to introduce itself and its buddy. Calling d.kidnap() will replace it's buddy with a new one. The important bit is to include this functionality while preserving Dog's functions test1() and test2(). The third call site in main() demonstrates that.
This all works. But I am unhappy with it. Line's 54 to 59 is where the problems are. See I would rather return self instead of having to create a whole new dog. When I attempt to do that I get all sorts of conflicting errors about the return type. I want to comment out line 52 and uncomment lines 54 to 59 and change either the return type of the function, the trait function definition, the impl definition of Dog<P> or something to make it work. I think I've tried all possibilities.
You can't return self because self is Dog<P> and your function says it returns Dog<Elephant<P>>. They are different types. You're not "initialising a new Dog", you're initialising a new Dog<Elephant<P>> because you don't already have one.
The code you have uncommented is the correct way to do it.
I've tried changing the signature of kidnap() to return Dog<P>. But that wont work because mismatched types. It obviously needs P but we give it Elephant<P>. We want to impl all Dog types of Dog<P> so it seems like this is impossible to express in Rust, though I hope I'm wrong. We have an impl for Dog<P> and we want to return Dog<P> where P = Elephant specifically.
It can't be Dog<P> because you're constructing a Dog<Elephant<P>>. The types must match exactly. It doesn't matter that Elephant<P> satisfies the constraint on P.
Also, you can't have the body of kidnap determine what P is. The caller decides what P it will use, and your function has to conform to that, and you don't know what P will be ahead of time.
If you're trying to write what you would in Java or C#, then you should stop and read through the Rust Book. Conventional OO designs do not translate well to Rust at all. Trying to do so usually leads to lots of beating your head against a wall and making no progress. You probably want to specifically read about trait objects, which might be closer to what you want. That said, keep in mind: traits are not interfaces (in the Java/C# sense), and trait objects aren't object references (in the Java/C# sense).