I would like to access my log::Log
impl instance in order to access a particular field, but once I receive the reference I am not able to downcast it to my struct.
I tried to convert the logger reference into core::any::Any
and then downcasting it into my original struct, but I always obtain None
.
use core::any::Any;
pub trait AToAny: 'static {
fn as_any(&self) -> &dyn Any;
}
impl<T: 'static> AToAny for T {
fn as_any(&self) -> &dyn Any {
self
}
}
struct MyLogger {}
impl log::Log for MyLogger {
fn enabled(&self, _: &log::Metadata<'_>) -> bool { todo!() }
fn log(&self, _: &log::Record<'_>) { todo!() }
fn flush(&self) { todo!() }
}
pub fn main() {
let logger_impl = MyLogger {};
log::set_boxed_logger(Box::new(logger_impl)).unwrap();
let logger = log::logger();
let logger_any = logger.as_any();
let logger_impl = logger_any.downcast_ref::<MyLogger>()
.expect("downcast failed");
}
I also tried without passing from log initialization functions, but I obtain the same result:
use core::any::Any; // 0.10.1
pub trait AToAny: 'static {
fn as_any(&self) -> &dyn Any;
}
impl<T: 'static> AToAny for T {
fn as_any(&self) -> &dyn Any {
self
}
}
struct MyLogger {}
impl log::Log for MyLogger {
fn enabled(&self, _: &log::Metadata<'_>) -> bool { todo!() }
fn log(&self, _: &log::Record<'_>) { todo!() }
fn flush(&self) { todo!() }
}
pub fn main() {
let logger_impl = MyLogger {};
let logger_boxed: Box<MyLogger> = Box::new(logger_impl);
let logger: &'static mut dyn log::Log = Box::leak(logger_boxed);
let logger_any = logger.as_any();
let logger_impl = logger_any.downcast_ref::<MyLogger>()
.expect("downcast failed");
}
Here is the code on the playground.
I saw that the type_id
of the logger
variable is different from the type_id
of the logger_impl
so I believe that this is what is preventing me from doing the downcast, but I cannot understant how I am supposed to fix this.
You're calling <&dyn Log>::as_any
, but you can only downcast that to &dyn Log
, that is logger_any.downcast_ref::<&dyn log::Log>()
returns Some
, but it gets you nowhere. A &dyn Log
does not expose the information necesary to downcast to MyLogger
.
Fortunately you don't need Any
or downcasting at all here since you can set the gobal logger with only a shared reference and still access the logger itself since shared references implement Copy
:
struct MyLogger {
bar: &'static str,
}
impl MyLogger {
fn foo(&self) {
println!("foo")
}
}
pub fn main() {
let logger: &MyLogger = Box::leak(Box::new(MyLogger { bar: "baz"}));
log::set_logger(logger as &dyn log::Log).unwrap(); // the cast is not needed, but illustrates what's happening implicitly otherwise.
logger.foo(); // can still call inherent MyLogger::foo
println!("{}", logger.bar); // and access fields.
}