Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: downcasting Log, but for real #666

Open
1e1001 opened this issue Feb 6, 2025 · 0 comments
Open

Feature Request: downcasting Log, but for real #666

1e1001 opened this issue Feb 6, 2025 · 0 comments

Comments

@1e1001
Copy link

1e1001 commented Feb 6, 2025

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant