Проблема с передачей изменяемой ссылки Arc в обработчик hyper service_fn

Я пробовал следующее

Соответствующий импорт и показанный код

use std::sync::{Arc, Mutex};
use std::thread;
use hyper::rt::{self, Future, Stream};
use hyper::service::service_fn;
use hyper::{Body, Request, Response, Server, StatusCode};

pub struct ChallengeState;
pub struct ChallengeResponse;

type BoxFut<'a> = Box<Future<Item = Response<Body>, Error = hyper::Error> + Send + 'a>;

fn handle_challengeproof<'a>(
    req: Request<Body>,
    challenge: &Arc<Mutex<ChallengeState>>,
) -> BoxFut<'a> {
    let resp = req.into_body().concat2().map(move |body| {
        let challenge_lock = challenge.lock().unwrap();
        Response::builder()
        .status(StatusCode::OK)
        .body(Body::from("test"))
        .unwrap()
    });
    Box::new(resp)
}

fn handle<'a>(
    req: Request<Body>,
    challenge: &Arc<Mutex<ChallengeState>>,
) -> BoxFut<'a> {
    handle_challengeproof(req, challenge)
}

pub fn run_listener(
    challenge: Arc<Mutex<ChallengeState>>,
) -> thread::JoinHandle<()> {
    let addr = ([127, 0, 0, 1], 9999).into();

    let listener_service = move || {
        let challenge = Arc::clone(&challenge);
        service_fn(move |req: Request<Body>| {
            handle(req, &challenge)
        })
    };

    let server = Server::bind(&addr)
        .serve(listener_service)
        .map_err(|_| () );

    thread::spawn(move || {
        rt::run(server);
    })
}

Я пытался избежать лишнего клона Arc, передавая ссылку на метод handle, но не могу этого избежать. Чтобы избежать времени жизни в handle (), возникла другая ошибка в отношении фьючерсов, запрашивающих статическое время жизни.

Код обновлен только релевантным материалом @ https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=10ea31450e88a122455006760d7fcdd1


person Nikos Kostoulas    schedule 14.03.2019    source источник
comment
ИМХО ссылка на Arc не имеет особого смысла. Вы либо передаете &ChallengeState, если хотите что-то с ним сделать, либо Arc, когда вам нужно его сохранить.   -  person hellow    schedule 14.03.2019
comment
Эта дуга используется совместно с другими темами. Я думаю о ссылке, чтобы избежать клонирования при каждом вызове service_fn.   -  person Nikos Kostoulas    schedule 14.03.2019
comment
Я обновил код, указав только на соответствующую проблему.   -  person Nikos Kostoulas    schedule 14.03.2019


Ответы (1)


Весь смысл Arc в том, что он подсчитывает количество ссылок, что происходит при его клонировании. Передача ссылок на Arc лишает смысла.

Вместо передачи ссылок передайте сам Arc. Итак, подпись handle становится:

fn handle<'a>(
    req: Request<Body>,
    challenge: Arc<Mutex<ChallengeState>>,
) -> BoxFut<'a>

Передача Arc по ссылкам из замыкания невозможна, потому что вы будете ссылаться на что-то, что немедленно выходит за рамки. Вместо этого переместите Arc в handle:

let listener_service = move || {
    service_fn(move |req: Request<Body>| handle(req, challenge))
}; 
person Peter Hall    schedule 14.03.2019
comment
Это создает другую проблему: это закрытие реализует FnOnce, а не Fn. Вызов нужно переносить каждый раз, а не один раз. - person Nikos Kostoulas; 14.03.2019
comment
@hellow извините, это в основном юнит-тесты. В любом случае проблема кажется довольно простой. Я передаю ссылку на Arc, и компилятор не может определить время жизни исходной Arc, чтобы проверить, совпадает ли его время жизни с тем, что я понимаю. - person Nikos Kostoulas; 14.03.2019
comment
@NikosKostoulas Можно ли сказать, что это минимальное воспроизведение или твоя проблема? - person Peter Hall; 14.03.2019
comment
да с &'a Arc<Mutex<ChallengeState>>, - person Nikos Kostoulas; 14.03.2019
comment
@NikosKostoulas Так это исправление вы ищете? play.rust-lang.org/ - person Peter Hall; 14.03.2019
comment
Да, но при использовании другого метода разблокировки Arc Mutex возникают дополнительные проблемы! play.rust-lang.org/ - person Nikos Kostoulas; 14.03.2019
comment
Странная проблема, правда? И когда я пытаюсь применить 'a срок жизни к вызову во всех методах, я получаю ошибку в run_listener. - person Nikos Kostoulas; 15.03.2019