[IFRT] Add `xla::ifrt::IoCallableProgram` type
[IFRT] Add `xla::ifrt::IoCallableProgram` type

`xla::ifrt::IoCallableProgram` represents a user program (tentatively named an
"I/O callable") that can be compiled into and executed as an
`xla::ifrt::LoadedExecutable`.

The main role of `IoCallableProgram` is to define a standard representation for
a range of programs that satisfy:

* Can be efficiently serialized into a string.
* Have a fixed list of devices used for executions. (**)
* All inputs and outputs are IFRT `Array`s.
* Have input and output array types statically known in advance to compilation
or execution. (**)
* Do not expect the IFRT user to help manage their internal state. The IFRT
user can destroy `xla::ifrt::LoadedExecutable` any time.

(**) indicates differences from more flexible `xla::ifrt::PluginProgram`.

Similar to how IFRT implementations decide whether to support specific IFRT
program types, the implementations can decide what the types of I/O callables
to support.
