use crate::{
Answer, Answers, Error, ErrorKind, Provider, Question, Questions, Request, Result, State,
TypedQuestion, ask,
};
#[derive(Clone, Debug)]
pub struct NamedQuestion {
name: String,
question: Question,
}
impl NamedQuestion {
pub fn new(name: impl Into<String>, question: impl Into<Question>) -> Result<Self> {
let name = name.into();
if name.is_empty() {
return Err(Error::new(
ErrorKind::InvalidArgument,
"operator name must not be empty",
));
}
Ok(Self {
name,
question: question.into(),
})
}
pub fn name(&self) -> &str {
&self.name
}
pub fn question(&self) -> &Question {
&self.question
}
}
#[derive(Clone, Debug)]
pub struct Operator<Q: TypedQuestion> {
name: String,
question: Q,
}
impl<Q: TypedQuestion> Operator<Q> {
pub fn new(name: impl Into<String>, question: Q) -> Result<Self> {
let name = name.into();
if name.is_empty() {
return Err(Error::new(
ErrorKind::InvalidArgument,
"operator name must not be empty",
));
}
Ok(Self { name, question })
}
pub fn name(&self) -> &str {
&self.name
}
pub fn question(&self) -> &Q {
&self.question
}
pub fn erased(&self) -> NamedQuestion {
NamedQuestion {
name: self.name.clone(),
question: self.question.clone().into(),
}
}
pub async fn ask<P: Provider + ?Sized>(
&self,
provider: &P,
state: &State,
) -> Result<Answer<Q::Output>> {
let request = Request::new(state.clone(), questions(&[self.erased()])?)?;
self.ask_request(provider, &request).await
}
pub async fn ask_request<P: Provider + ?Sized>(
&self,
provider: &P,
request: &Request,
) -> Result<Answer<Q::Output>> {
let request = request.with_questions(questions(&[self.erased()])?)?;
let answers = ask(provider, &request).await?;
self.answer(&answers)
}
pub fn answer(&self, answers: &Answers) -> Result<Answer<Q::Output>> {
answers
.get(&self.name)
.ok_or_else(|| {
Error::new(
ErrorKind::InvalidArgument,
"operator is absent from the answer batch",
)
})?
.revalidate(&self.question.clone().into())?
.typed()
}
}
pub fn questions(operators: &[NamedQuestion]) -> Result<Questions> {
if operators.is_empty() {
return Err(Error::new(
ErrorKind::InvalidArgument,
"operator batch must not be empty",
));
}
let mut result = Questions::new();
for operator in operators {
if result
.insert(operator.name.clone(), operator.question.clone())
.is_some()
{
return Err(Error::new(
ErrorKind::InvalidArgument,
"operator names must be unique",
));
}
}
Ok(result)
}
pub async fn apply<P: Provider + ?Sized>(
provider: &P,
request: &Request,
operators: &[NamedQuestion],
) -> Result<Answers> {
ask(provider, &request.with_questions(questions(operators)?)?).await
}