Давайте начнем с очистки нескольких вещей:
не похоже на способ написания однопоточного кода Tokio, который избегает мьютексов
Требование Mutex
не имеет ничего общего с однопоточностью, но с изменчивыми заимствованиями. Всякий раз, когда вы порождаете будущее, это будущее является его собственной сущностью;он магически не является частью вашего struct
, и большинство определенно не знает, как сохранить &mut self
. В этом смысл Mutex
- он позволяет вам динамически получать изменяемую ссылку на внутреннее состояние - а Arc
позволяет вам иметь доступ к самому Mutex
в нескольких местах.
ИхКстати, несинхронизированными эквивалентами являются Rc
и Cell
/ RefCell
, а их содержимое (синхронизированное или несинхронизированное) должно принадлежать типу.
Требование Send
действительно отображаетсякогда вы используете futures
поверх tokio
, так как Executor
требует, чтобы на нем появилось фьючерсы Send
(по понятным причинам - вы могли бы сделать spawn_local
, но это вызовет больше проблем, чем решит).
Теперь вернемся к вашей проблеме. Я дам вам кратчайший путь к ответу на вашу проблему. Это, однако, не будет полностью правильным способом делать вещи;однако, поскольку я не знаю, какой протокол вы собираетесь установить поверх TcpStream
или какие у вас требования, я не могу указать вам правильное направление (пока). По этой причине есть комментарии - дайте мне больше требований, и я с радостью отредактирую это!
В любом случае. Вернуться к проблеме. Поскольку Mutex<_>
лучше использовать с собственным типом, мы собираемся сделать это прямо сейчас и "исправить" ваши Reader
и Writer
:
pub struct Reader {
session: Arc<RwLock<Session>>,
read_half: ReadHalf<TcpStream>,
}
pub struct Writer {
session: Arc<RwLock<StompSession>>,
write_half: WriteHalf<TcpStream>,
}
Поскольку мы изменили это, мытакже необходимо отразить это в другом месте, но для того, чтобы сделать это, нам нужно будет потреблять self
. Это нормально, однако, так как мы собираемся иметь копию Arc<Mutex<_>>
в любом объекте, который мы возвращаем:
impl Session {
pub fn split(self, sock: TcpStream) -> (Reader, Writer) {
let (read_half, write_half) = sock.split();
let session = Arc::new(RwLock::new(self));
( Reader::new(session.clone(), read_half), Writer::new(session, write_half) )
}
}
И вот, он компилируется и каждая пара Writer
/ Reader
теперь есть собственная заимствованная (изменяемая и не изменяемая) ссылка на нашу сессию!
Фрагмент детской площадки выделяет сделанные изменения. Как я уже сказал, он работает сейчас, но он укусит вас в задницу в тот момент, когда вы попытаетесь что-то сделать, поскольку вам понадобится что-то поверх обоих ReadHalf
и WriteHalf
, чтобы иметь возможность использовать их правильно.