Looks like big_endian() returns a serializer borrowing from the config; if so, the config needs to be kept alive while the serializer is. In your first case, config() returns a config that’s going to be dropped on that line since it’s a temporary and not kept alive by anything.
&mut Self return means you’re holding a mutable borrow of it, but we need an owner to borrow from; the owner here, result of config(), is a temp that dies.
The compiler doesn’t keep temps alive in constructs like this. Your ser is a &mut Serializer, which as mentioned means you’re borrowing the Serializer mutably from somewhere else. That somewhere else needs to be alive.
Rust does allow constructs like this though:
let v = &mut vec![1,2,3];
I’m not sure how it’s actually implemented in the compiler, but you can imagine a desugaring like:
where as_mut_slice has a similar signature to big_endian, then the same error would be raised.
Which essentially means that builder pattern would not work.
It is interesting that if I cascade that "temporary" to serialize function then there would no problem and it would compile.
let mut bytes = config().big_endian().serialize(&req)?;
That’s because bytes has no references and so the “temp dropped at statement end” is ok.
The issue of temp (rvalue) lifetimes is a known papercut. The case I’ve seen reported a few times in particular is usage of std::io::stdout().lock()...
Also, this might be a reason to prefer the builder pattern where you take and return self by value, rather than reference (that’s what I was going to suggest if this was your code).