-> bool (это необязательно, есть определённая свобода выбора, впрочем пусть это будет стартовой точкой), нужно сделать из неё указатель на функцию fn(B) -> bool(это уже менять нельзя). Можно сконвертировать B в A, скажем A::from_b(b: B).
Попытка написать обёртку сразу же заканчивается неудачей:
fn convert(f: fn(A) -> bool) {
let f_new = move |b: B| f(A::from_b(b));
some_api(f_new) // облом, ожидался указатель на функцию, получили замыкание
}
Так вот, я размышляю над этой проблемой, одна сумасшедшая идея такая — определить f_new как generic функцию:
fn f_new<F>(b: B) -> bool {
let f = [указатель на старую функцию получить из F];
f(A::from_b(b)
}
Дело за малым — получить указатель на функцию из дженерик-параметра.
Есть ещё гипотетический способ передать через глобальный thread_local сторадж, но тоже возникает масса вопросов, как потом удалять указатели на функции, которые больше не нужны.
Для удобства, пример на плейграунде, (WARNING: сейчас не компилируется)
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=d352c38adf255c5066ab4578cfdd6865
Почему бы не брать параметр f: F? Еще, на найтли я бы попробовал фичу с названием типа unboxed_fn_traits, и тогда let f = |x| { assert_eq!(size_of::<F>(), 0;) F::call(unsafe{ &std::mem::zeroed() }, x)} по идее должно работатт
Можно и f: F, но тогда возникнет ещё дополнительная проблема, куда девать контекст.
fn convert_and_call<F: Fn(A) -> bool>(f: F) { let f_new = move |b: B| { F::call(&f, (A::from_b(b),)) // f(A::from_b(b)) }; some_api(f_new) } Ничего не поменялось в плане ошибки: также expected fn pointer found closure
Да и потом, вдруг F = !, тогда код unsound
Если брать f: F аргументом, то мы точно знаем что F населен и его инстансы можно создавать
А брать такой аргумент все равно придется, чтобы указать тип входной функции
Если обёртка для апи хочет через обычные функции каллбэк принимать, то наверное не получится. Либо в динамике генерировать обёртку либо передавать поинтер через тред локал. С другой стороны если каллбэк передавать через трейт с одной статической функцией то может сработать.
Но это не удобно с точки зрения пользователя. Каждый раз создавать пустую структуру с трейтом для этого
Да, я уже обозначил эти альтернативы.
Ещё одна: PR в библиотеку, чтобы был вариант API, принимающий указатель на контекст.
Прикольный вариант. Да, если с указателем на контекст, то можно сразу брать эту технику оборачивания, довольно интересный трюк.
Обсуждают сегодня