Hi Symon,
for (most) of the given examples case and if-elsif will give the same result.
Why?
Because in both cases

your selector is fully covered (uses all of the bits of a vector or whatever you use as a
selector). Your if-elsif collapses into a parallel structure, because there is no priority of one value over the other
possible.
but how about this:
Selector <= A&B&C; -- I MUST do this for a case statement !
case Selector is
when "001" => Output <= Input1;
when "010" => Output <= Input2;
when "100" => Output <= Input2;
when others => Output <= (others => 'Z');
end case;
vs.
If C = '1' then
Output <= Input1;
elsif B= '1' then
Output <= Input2;
elsif C= '1' then
Output <= Input3;
else
Output <= (others => 'Z');
end if;
NOW the case produces a parallel multiplexer structure that is sensitive for the given code of Selector.
The if-elsif does something different. Whenever C becomes '1' (No matter how unlikely or unneccesary this might be in
your particular design) it switches Input1 to the output. Here we have the always cited priority encoder.
To get the same functionality with a case you have to write a different code:
Selector <= A&B&C; -- I MUST do this for a case statement !
case Selector is
when "--1" => Output <= Input1;
when "-10" => Output <= Input2;
when "100" => Output <= Input2;
when others => Output <= (others => 'Z');
end case;
Now the first >when< hits whenever C becomes '1'.
This code might produce something more "parallel" than the if-elsif, but who knows about the tricks of modern synthesis
tools.
Have a nice synthesis
Eilert