Make Plugin::ask take self instead of &mut self

This commit is contained in:
Lutetium-Vanadium 2021-06-27 16:51:05 +05:30
parent 893037fbfe
commit 08353945e5
2 changed files with 44 additions and 12 deletions

View File

@ -28,6 +28,7 @@ pub use choice::Choice;
use choice::{get_sep_str, ChoiceList};
use options::Options;
pub use plugin::Plugin;
use plugin::PluginInteral;
use ui::{backend::Backend, error, events::KeyEvent};
use std::fmt;
@ -39,7 +40,7 @@ pub struct Question<'a> {
}
impl<'a> Question<'a> {
pub(crate) fn new(opts: Options<'a>, kind: QuestionKind<'a>) -> Self {
fn new(opts: Options<'a>, kind: QuestionKind<'a>) -> Self {
Self { kind, opts }
}
}
@ -85,17 +86,18 @@ impl Question<'static> {
EditorBuilder::new(name.into())
}
pub fn plugin<'a, N, P>(name: N, plugin: P) -> PluginBuilder<'a>
pub fn plugin<'a, N, P, I>(name: N, plugin: I) -> PluginBuilder<'a>
where
N: Into<String>,
P: Into<Box<dyn Plugin + 'a>>,
P: Plugin + 'a,
I: Into<P>,
{
PluginBuilder::new(name.into(), plugin.into())
PluginBuilder::new(name.into(), Box::new(Some(plugin.into())))
}
}
#[derive(Debug)]
pub(crate) enum QuestionKind<'a> {
enum QuestionKind<'a> {
Input(input::Input<'a>),
Int(number::Int<'a>),
Float(number::Float<'a>),
@ -106,8 +108,7 @@ pub(crate) enum QuestionKind<'a> {
Checkbox(checkbox::Checkbox<'a>),
Password(password::Password<'a>),
Editor(editor::Editor<'a>),
// random lifetime so that it doesn't have to be static
Plugin(Box<dyn Plugin + 'a>),
Plugin(Box<dyn PluginInteral + 'a>),
}
impl Question<'_> {

View File

@ -4,6 +4,23 @@ use super::{Options, Question, QuestionKind};
use crate::{Answer, Answers};
pub trait Plugin: std::fmt::Debug {
fn ask(
self,
message: String,
answers: &Answers,
stdout: &mut dyn Backend,
events: &mut dyn Iterator<Item = error::Result<events::KeyEvent>>,
) -> error::Result<Answer>;
}
/// The same trait as `Plugin`, except it take `&mut self` instead of `self`.
///
/// This is required since traits with functions that take `self` are not object safe, and so
/// implementors of the trait would have to use &mut self even though it will only be called once.
///
/// Now instead of QuestionKind::Plugin having a `dyn Plugin`, it has a `dyn PluginInteral`, which
/// is an `Option<T: Plugin>`.
pub(super) trait PluginInteral: std::fmt::Debug {
fn ask(
&mut self,
message: String,
@ -13,19 +30,33 @@ pub trait Plugin: std::fmt::Debug {
) -> error::Result<Answer>;
}
pub struct PluginBuilder<'a> {
opts: Options<'a>,
plugin: Box<dyn Plugin + 'a>,
impl<T: Plugin> PluginInteral for Option<T> {
fn ask(
&mut self,
message: String,
answers: &Answers,
stdout: &mut dyn Backend,
events: &mut dyn Iterator<Item = error::Result<events::KeyEvent>>,
) -> error::Result<Answer> {
self.take()
.expect("Plugin::ask called twice")
.ask(message, answers, stdout, events)
}
}
impl<'a, P: Plugin + 'a> From<P> for Box<dyn Plugin + 'a> {
pub struct PluginBuilder<'a> {
opts: Options<'a>,
plugin: Box<dyn PluginInteral + 'a>,
}
impl<'a, P: PluginInteral + 'a> From<P> for Box<dyn PluginInteral + 'a> {
fn from(plugin: P) -> Self {
Box::new(plugin)
}
}
impl<'a> PluginBuilder<'a> {
pub(crate) fn new(name: String, plugin: Box<dyn Plugin + 'a>) -> Self {
pub(super) fn new(name: String, plugin: Box<dyn PluginInteral + 'a>) -> Self {
Self {
opts: Options::new(name),
plugin,