Description
Seems #399 was already closed (4.5 years ago, for bad usecase & maybe backwards compatibility reasons?), but I have an actual use!
My logger writes a message on panic, but does so with a custom format different to anything you can write with the Log
trait. So I need to be able to downcast the &dyn Log
into my own logger from the panic handler. I could probably use a OnceLock
to store if my logger's been initialized but log
already does that with the (set_
)logger
methods, so it feels redundant.
For now my current way of doing this is this very cursed set of functions:
fn as_dyn_ref(logger: *const Logger) -> *const dyn Log {
// split into one function to always attach the same metadata
logger as *const dyn Log
}
fn upcast_log(logger: &'static Logger) -> &'static dyn Log {
// SAFETY: as_dyn_ref returns a reference to the same object as passed in
unsafe { &*as_dyn_ref(logger) }
}
fn downcast_log(log: &'static dyn Log) -> Option<&'static Logger> {
// horribly cursed implementation to fetch a reference to the installed logger
let (logger_ptr, logger_meta) = (&raw const *log).to_raw_parts();
let (_, fake_logger_meta) = as_dyn_ref(ptr::null::<Logger>()).to_raw_parts();
(logger_meta == fake_logger_meta).then(|| {
// SAFETY: v-tables match so it's probably ours!
unsafe { &*logger_ptr.cast::<Logger>() }
})
}
but that's a lot of unsafe, and nightly-only.
To prevent needing to add a + 'static
bound on Log
(which probably breaks compatibility somehow), yandros suggested (in rplcs #dark-arts) adding something like:
fn type_id(&self) -> TypeId
where Self: 'static
{
TypeId::of<Self>()
}
as an automatic implementation on the Log
trait.