Hi all, I am trying to build a Option of a boxed trait object based on an enum, however I can't manage to get rid of the move error or the only can get a reference of the trait object:
let emitter_dest = match &config.diagnostic_output {
DiagnosticOutput::Default => None,
DiagnosticOutput::Raw(dest) => Some(*dest.clone()),
};
The diagnosticoutput is a type in rustc, when the enum is Raw variant it contains a Box<dyn Write + Send>, I will need to cast it to None (Default), or Some(Box<dyn Write + Send>), how can I do that? The code I posted get this error:
DiagnosticOutput::Raw(dest) => Some(*dest.clone()),
| ^^^^^^^^^^^^^ move occurs because value has type `std::boxed::Box<dyn std::io::Write + std::marker::Send>`, which does not implement the `Copy` trait
If I do:
let emitter_dest = match &config.diagnostic_output {
DiagnosticOutput::Default => None,
DiagnosticOutput::Raw(dest) => Some(dest.clone()),
};
Maybe you should also give us more information about how/where emitter_dest is used. If that's a struct or a function expecting Option<Box<dyn Write + Send>>, so in particular an owned value, this means that you would need to move that Box out of the config.diagnostic field. Since that does (as you describe) already contain a trait object, you cannot just clone it. Your call to clone is basically doing nothing here, just copying a shared/immutable reference (“&T”). Now do you want to consume config here? What's the context?
A more complete presentation of the relevant code would help us help you. In case you do want to preserve config (not take ownership over its diagnostic_output field), then its just impossible to get an owned Option<Box<dyn Write + Send>> out of it that's passed to wherever emitter_dest is passed to and you need to change some struct definitions or function signatures involved.
Is there a way to move the box out of the diagnostic_output field given that the field doesn't impl Clone too? I am not sure that field is going to be used directly anyway so maybe I can move that data out and create emitter with it.
I see. I'm not familiar with these compiler libraries myself, but judging by the types involved, it might be a viable option to duplicate the dyn Write trait object by creating two handles that will merge into the original writer. Maybe using an Arc<Mutex<Box<dyn Write + Send>> with a wrapper that implements Write? Maybe add LineWriter to possibly reduce locking overhead and to avoid too much of a mess if two things want to write at the same time?
If you want to "steal" the contents of the field, that's possible. E. g. using mem::replace. You must leave something in place of the thing you took, in this case probably the ::Default variant of the enum? It does modify the config though. I don't know what effect that could/would have in your setting.
In case you try it, this approach involves mem::replace as well in order to gain ownership of the Box<dyn Write + Send>, just that afterwards, you put back one of the two writers you’ve created in order to keep the config “intact”.