consider the following snippet code,
the msg_builder holds the mutable reference to the member variable of MsgA, and calling the msg.check() will require the immutable borrow of MsgA.
use bytes::*;
use std::any::Any;
type Encoder<'a> = Box<dyn FnMut(&mut BytesMut) + 'a>;
type Decoder<'a> = Box<dyn FnMut(&mut Bytes) + 'a>;
pub trait IE {
fn encode(ie: &Self, stream: &mut BytesMut)
where
Self: Sized;
fn decode(stream: &mut Bytes) -> Self
where
Self: Sized;
fn as_any(&self) -> &dyn Any;
}
#[derive(Debug, Clone, Copy)]
pub struct MyIEa {
num: u32,
}
impl IE for MyIEa {
fn decode(stream: &mut Bytes) -> Self
where
Self: Sized,
{
println!("MyIEa::decode");
MyIEa {
num: stream.get_u32(),
}
}
fn encode(ie: &Self, stream: &mut BytesMut)
where
Self: Sized,
{
stream.put_u32(ie.num);
println!("MyIEa::encode: {:?}", ie);
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub trait SerialMsg {
fn check_it(&self);
fn on_build<'a: 'b, 'b>(&'a mut self, msg_builder: &mut MsgBuilder<'b>);
}
pub struct MsgA {
ie_a: MyIEa,
}
impl SerialMsg for MsgA {
fn on_build<'a: 'b, 'b>(&'a mut self, msg_builder: &mut MsgBuilder<'b>) {
msg_builder.mandatory_ie(&mut self.ie_a);
}
fn check_it(&self) {
let _ = self;
}
}
pub struct MsgBuilder<'a> {
pub msg_encoders: Vec<Encoder<'a>>,
pub msg_decoders: Vec<Decoder<'a>>,
pub msg_opt_encoders: Vec<Encoder<'a>>,
pub msg_opt_decoders: Vec<Decoder<'a>>,
}
impl<'a> MsgBuilder<'a> {
pub fn new() -> Self {
MsgBuilder {
msg_encoders: Vec::new(),
msg_decoders: Vec::new(),
msg_opt_encoders: Vec::new(),
msg_opt_decoders: Vec::new(),
}
}
pub fn mandatory_ie<X: IE + Clone + 'static>(&mut self, ie: &'a mut X) {
let ie_cloned = ie.clone();
// for encoder
let encoder = move |stream: &mut BytesMut| {
let t = ie_cloned
.as_any()
.downcast_ref::<X>()
.expect("mandatory_ie, T:IE != ie: &mut dyn IE");
X::encode(t, stream);
};
self.msg_encoders.push(Box::new(encoder));
// for decoder
let decoder = |stream: &mut Bytes| {
let ie_x = X::decode(stream);
ie.clone_from(&ie_x);
};
self.msg_decoders.push(Box::new(decoder));
}
pub fn optional_ie<X: IE + Clone + 'static>(&mut self, ie: &'a mut Option<X>) {
if ie.is_some() {
let ie = ie.clone().unwrap();
// for encoder
let encoder = move |stream: &mut BytesMut| {
let t = ie
.as_any()
.downcast_ref::<X>()
.expect("optional_ie, T:IE != ie: &mut dyn IE");
X::encode(t, stream);
};
self.msg_opt_encoders.push(Box::new(encoder));
}
// for decoder
let decoder = |stream: &mut Bytes| {
let ie_x = X::decode(stream);
ie.clone_from(&Some(ie_x));
};
self.msg_opt_decoders.push(Box::new(decoder));
}
}
fn test_ex17() {
let mut msg = MsgA { ie_a: MyIEa { num: 100 }, };
{
let mut stream = Bytes::new();
let mut stream_mut = BytesMut::new();
let mut msg_builder = MsgBuilder::new();
msg.on_build(&mut msg_builder);
for mut decoder in msg_builder.msg_opt_decoders {
decoder(&mut stream);
}
for mut encoeder in msg_builder.msg_opt_encoders {
msg.check_it();
encoeder(&mut stream_mut);
}
}
}
the compiler complains that:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `msg` as immutable because it is also borrowed as mutable
--> src/lib.rs:146:13
|
139 | msg.on_build(&mut msg_builder);
| ------------------------------ mutable borrow occurs here
...
146 | msg.check_it();
| ^^^^^^^^^^^^^^ immutable borrow occurs here
...
149 | }
| - mutable borrow might be used here, when `msg_builder` is dropped and runs the destructor for type `MsgBuilder<'_>`
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error
here is the playground url: