Возврат RWLockReadGuard независимо от метода - PullRequest
0 голосов
/ 23 мая 2018

У меня есть объект типа

Arc<RwLock<SessionData>>

И у меня есть метод, который должен принимать какую-то ссылку на SessionData

fn some_method(session: ...)

Я использую Rocket(веб-фреймворк для Rust), и я не могу напрямую вызвать метод, потому что он вызывается Rocket.Тем не менее, я могу предоставить ему реализацию, которая создает объект, который будет передан обработчику.Это выглядит примерно так:

impl<'a, 'r> request::FromRequest<'a, 'r> for SomeType {
    type Error = ();

    fn from_request(request: &'a request::Request<'r>) -> request::Outcome<Self, Self::Error> {
        // return object here
    }
}

Я хочу не возвращать RwLock напрямую, потому что я хочу, чтобы обработчик передавал ему уже заблокированный объект.Однако я не могу вернуть ссылку или RwLockReadGuard, потому что они оба зависят от RwLock, который выходит за рамки.

Вместо этого я пытаюсь создать какое-то сам-подходящий тип, который будет содержать Arc<RwLock<SessionData>>, содержать защитную блокировку для этой блокировки и разыменовать объект SessionData.

До сих пор я пробовал некоторые комбинации из следующих:

  • A Session объект, который содержит Arc<RwLock<SessionData>> и RwLockReadGuard<SessionData>
  • Объект, который содержит Arc<RwLock<SessionData>> и RwLockReadGuardRef<SessionData> из owning ref library.
  • Объект, который будет использовать тип OwnedHandle из библиотеки owning-ref .

Однако я не смогделать то, что я хочу делать, сталкиваясь с различными проблемами заимствования и тому подобное.

Возможно ли вообще создать что-то вроде автономного «дескрипторного» объекта, который будет содержать какблокировка и блокировка защиты объекта, на который он указывает?

Это похоже, но немного отличаетсяДругая ситуация, чем описано в Как вернуть ссылку на подзначение значения, находящегося в мьютексе? .Там MutexGuardRef внутренне зависит от Mutex и не может существовать, если Mutex (или MyStruct) выходит из области видимости.Чтобы добиться подобного поведения, я должен передать структуру, содержащую мой RwLock, а затем выполнить блокировку внутри метода.Это нормально, но мне интересно, могу ли я пойти еще дальше и передать структуру, которая является независимой и служит RwLockGuard, избегая необходимости блокироватьвручную.

По сути, я хочу перенести блокировку RwLock с клиента на поставщика значения.

1 Ответ

0 голосов
/ 24 мая 2018

Как описано в Почему я не могу сохранить значение и ссылку на это значение в одной и той же структуре? , Ящик для аренды допускает в некоторых случаях самоссылочные структуры.

#[macro_use]
extern crate rental;

use std::sync::{Arc, RwLock};

struct SessionData;
impl SessionData {
    fn hello(&self) -> u8 { 42 }
}

rental! {
    mod owning_lock {
        use std::sync::{Arc, RwLock, RwLockReadGuard};

        #[rental(deref_suffix)]
        pub struct OwningReadGuard<T>
        where
            T: 'static,
        {
            lock: Arc<RwLock<T>>,
            guard: RwLockReadGuard<'lock, T>,
        }
    }
}

use owning_lock::OwningReadGuard;

fn owning_lock(session: Arc<RwLock<SessionData>>) -> OwningReadGuard<SessionData> {
    OwningReadGuard::new(session, |s| s.read().unwrap())
}

fn main() {
    let session = Arc::new(RwLock::new(SessionData));

    let lock = owning_lock(session.clone());
    println!("{}", lock.hello());

    assert!(session.try_read().is_ok());
    assert!(session.try_write().is_err());

    drop(lock);

    assert!(session.try_write().is_ok());
}

См. Также:

...