semantic_operators/
provider.rs1use crate::{Answer, Error, ErrorKind, IndexMap, Question, Result, State};
4use std::{future::Future, pin::Pin, sync::Arc};
5
6pub type Questions = IndexMap<String, Question>;
8pub type Answers = IndexMap<String, Answer>;
10pub type ProviderFuture<'a> = Pin<Box<dyn Future<Output = Result<Answers>> + Send + 'a>>;
12
13#[derive(Clone)]
15pub struct Request {
16 state: State,
17 questions: Questions,
18 #[cfg(feature = "images")]
19 assets: crate::image::Assets,
20}
21impl std::fmt::Debug for Request {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 f.debug_struct("Request")
24 .field("question_count", &self.questions.len())
25 .finish_non_exhaustive()
26 }
27}
28impl Request {
29 pub fn new(state: State, questions: Questions) -> Result<Self> {
36 if questions.is_empty() || questions.keys().any(String::is_empty) {
37 return Err(Error::new(
38 ErrorKind::InvalidArgument,
39 "a request needs nonempty, uniquely named questions",
40 ));
41 }
42 Ok(Self {
43 state,
44 questions,
45 #[cfg(feature = "images")]
46 assets: Default::default(),
47 })
48 }
49 pub fn state(&self) -> &State {
51 &self.state
52 }
53 pub fn questions(&self) -> &Questions {
55 &self.questions
56 }
57 pub fn with_questions(&self, questions: Questions) -> Result<Self> {
63 let request = Self::new(self.state.clone(), questions)?;
64 #[cfg(feature = "images")]
65 let request = request.with_assets(self.assets.clone());
66 Ok(request)
67 }
68 #[cfg(feature = "images")]
70 #[cfg_attr(docsrs, doc(cfg(feature = "images")))]
71 pub fn with_assets(mut self, assets: crate::image::Assets) -> Self {
72 self.assets = assets;
73 self
74 }
75 #[cfg(feature = "images")]
77 #[cfg_attr(docsrs, doc(cfg(feature = "images")))]
78 pub fn assets(&self) -> &crate::image::Assets {
79 &self.assets
80 }
81 pub fn validate(&self) -> Result<()> {
88 #[cfg(feature = "images")]
89 self.assets.validate(&self.state, &self.questions)?;
90 Ok(())
91 }
92}
93
94pub trait Provider: Send + Sync {
97 fn ask<'a>(&'a self, request: &'a Request) -> ProviderFuture<'a>;
104}
105impl<P: Provider + ?Sized> Provider for Arc<P> {
106 fn ask<'a>(&'a self, request: &'a Request) -> ProviderFuture<'a> {
107 (**self).ask(request)
108 }
109}
110
111pub async fn ask<P: Provider + ?Sized>(provider: &P, request: &Request) -> Result<Answers> {
117 request.validate()?;
118 validate_answers(request, provider.ask(request).await?)
119}
120pub fn validate_answers(request: &Request, answers: Answers) -> Result<Answers> {
126 if answers.len() != request.questions.len()
127 || answers
128 .keys()
129 .any(|name| !request.questions.contains_key(name))
130 {
131 return Err(Error::new(
132 ErrorKind::InvalidResponse,
133 "provider must answer exactly the requested question names",
134 ));
135 }
136 request
137 .questions
138 .iter()
139 .map(|(name, question)| {
140 let answer = answers.get(name).ok_or_else(|| {
141 Error::new(
142 ErrorKind::InvalidResponse,
143 "provider omitted a requested answer",
144 )
145 })?;
146 Ok((name.clone(), answer.revalidate(question)?))
147 })
148 .collect()
149}
150
151pub struct FunctionProvider<F> {
153 function: F,
154}
155impl<F> FunctionProvider<F>
156where
157 F: for<'a> Fn(&'a Request) -> ProviderFuture<'a> + Send + Sync,
158{
159 pub fn new(function: F) -> Self {
161 Self { function }
162 }
163}
164impl<F> Provider for FunctionProvider<F>
165where
166 F: for<'a> Fn(&'a Request) -> ProviderFuture<'a> + Send + Sync,
167{
168 fn ask<'a>(&'a self, request: &'a Request) -> ProviderFuture<'a> {
169 Box::pin(async move { (self.function)(request).await })
170 }
171}
172
173#[cfg(feature = "tokio")]
177pub(crate) async fn deadline<F: Future>(
178 duration: std::time::Duration,
179 future: F,
180) -> Result<F::Output> {
181 if tokio::runtime::Handle::try_current().is_err() {
182 return Err(Error::new(
183 ErrorKind::Runtime,
184 "deadline requires a time-enabled Tokio runtime",
185 ));
186 }
187 let timer = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
188 tokio::time::timeout(duration, future)
189 }))
190 .map_err(|_| Error::new(ErrorKind::Runtime, "Tokio timer driver is not enabled"))?;
191 timer
192 .await
193 .map_err(|_| Error::new(ErrorKind::Timeout, "provider call exceeded its deadline"))
194}