Skip to content

Feature Request: downcasting Log, but for real #666

Open
@1e1001

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.

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions