> +impl ClassInitImpl<PL011Class> for PL011State {
> + fn class_init(klass: &mut PL011Class) {
> + klass.device_id = DeviceId::ARM;
> + <Self as ClassInitImpl<SysBusDeviceClass>>::class_init(&mut klass.parent_class);
This seems a bit of a conflict with the C version of QOM semantics. In C,
class_init is registered in TypeInfo, and then the QOM code will
automatically call the parent's class_init without needing to explicitly
call the parent's in the child's class_init.
This is the same in Rust.
The difference is that in C you have a single class_init function that sets all members of ObjectClass, DeviceClass, etc. In Rust each class has one trait and there is a chain of ClassInitImpl implementations—one filling in "oc" from ObjectImpl, one filling in "dc" from DeviceImpl and so on.
But in both cases you get a chain of calls from qom/object.c.
Therefore, the call here seems valid from the code logic's perspective.
But, when there is deeper class inheritance, it seems impossible to
prevent class_init from being called both by the C side's QOM code and by
this kind of recursive case on the Rust side.
Note that here you have two parameters: what class is being filled (the argument C of ClassInitImpl<C>) *and* what type is being initialized (that's Self).
The "recursion" is only on the argument C, and matches the way C code implements class_init.
Maybe the confusion is because I implemented class_init twice instead of using a separate trait "PL011Impl"?
Paolo
So, for devices like SysBusDevice that are registered on the C side,
should we not implement class_init and also not call it explicitly?
Or should we distinguish between two different usages of class_init? One
is registered in TypeInfo (only as a callback in rust_class_init) - perhaps
rename it as qom_class_init, and the other is used as a helper for Rust-side
calls (similar to the recursive usage here) - maybe rename it as
class_inter_init.
> + }
> +}