I want to implement Writer-Reader pattern decoupled with a Channel. The problem is that Rust allows only 1 mutable reference at a time, but Writer must be able to write to the channel and Reader must be able to remove a value that it just read. Is there a conceptual violation of Rust assumptions?
Here is the code that expectedly can’t be compiled:
<code>// Channel
impl Channel {
fn write(&mut self, value: &str) {
self.queue.push(value.to_string());
}
fn read(&mut self) -> Option<String> {
if !self.queue.is_empty() {
Some(self.queue.remove(self.queue.len() - 1))
} else {
None
}
}
}
impl Channel {
fn new() -> Self {
Self {
queue: vec!()
}
}
}
// Writer
struct Writer<'a> {
channel: &'a mut Channel
}
impl<'a> Writer<'a> {
fn new(channel: &'a mut Channel) -> Self {
Self {
channel
}
}
fn write(&mut self, value: &str) {
self.channel.write(value);
}
}
// Reader
struct Reader<'a> {
channel: &'a mut Channel
}
impl<'a> Reader<'a> {
fn new(channel: &'a mut Channel) -> Self {
Self {
channel
}
}
fn read(&mut self) {
if let Some(value) = self.channel.read() {
print!("Read {}", value)
}
}
}
struct Channel {
queue: Vec<String>
}
fn main() {
let mut channel = Channel::new();
let mut writer = Writer::new(&mut channel);
let mut reader = Reader::new(&mut channel); // cannot borrow `channel` as mutable more than once at a time
writer.write("test_value");
reader.read();
}
</code>
<code>// Channel
impl Channel {
fn write(&mut self, value: &str) {
self.queue.push(value.to_string());
}
fn read(&mut self) -> Option<String> {
if !self.queue.is_empty() {
Some(self.queue.remove(self.queue.len() - 1))
} else {
None
}
}
}
impl Channel {
fn new() -> Self {
Self {
queue: vec!()
}
}
}
// Writer
struct Writer<'a> {
channel: &'a mut Channel
}
impl<'a> Writer<'a> {
fn new(channel: &'a mut Channel) -> Self {
Self {
channel
}
}
fn write(&mut self, value: &str) {
self.channel.write(value);
}
}
// Reader
struct Reader<'a> {
channel: &'a mut Channel
}
impl<'a> Reader<'a> {
fn new(channel: &'a mut Channel) -> Self {
Self {
channel
}
}
fn read(&mut self) {
if let Some(value) = self.channel.read() {
print!("Read {}", value)
}
}
}
struct Channel {
queue: Vec<String>
}
fn main() {
let mut channel = Channel::new();
let mut writer = Writer::new(&mut channel);
let mut reader = Reader::new(&mut channel); // cannot borrow `channel` as mutable more than once at a time
writer.write("test_value");
reader.read();
}
</code>
// Channel
impl Channel {
fn write(&mut self, value: &str) {
self.queue.push(value.to_string());
}
fn read(&mut self) -> Option<String> {
if !self.queue.is_empty() {
Some(self.queue.remove(self.queue.len() - 1))
} else {
None
}
}
}
impl Channel {
fn new() -> Self {
Self {
queue: vec!()
}
}
}
// Writer
struct Writer<'a> {
channel: &'a mut Channel
}
impl<'a> Writer<'a> {
fn new(channel: &'a mut Channel) -> Self {
Self {
channel
}
}
fn write(&mut self, value: &str) {
self.channel.write(value);
}
}
// Reader
struct Reader<'a> {
channel: &'a mut Channel
}
impl<'a> Reader<'a> {
fn new(channel: &'a mut Channel) -> Self {
Self {
channel
}
}
fn read(&mut self) {
if let Some(value) = self.channel.read() {
print!("Read {}", value)
}
}
}
struct Channel {
queue: Vec<String>
}
fn main() {
let mut channel = Channel::new();
let mut writer = Writer::new(&mut channel);
let mut reader = Reader::new(&mut channel); // cannot borrow `channel` as mutable more than once at a time
writer.write("test_value");
reader.read();
}
Playground
What’s the right way of doing that in Rust?
PS. It’s mean to be executed in single-thread environment.