1use core::marker::PhantomData;
11
12pub trait Query {
13 fn execute(&mut self, context: &dyn core::any::Any) -> ControlFlow;
14}
15
16pub trait QueryMut {
17 fn execute_mut(&mut self, context: &mut dyn core::any::Any) -> ControlFlow;
18}
19
20#[derive(Debug, Clone, Copy, PartialEq)]
22pub enum ControlFlow {
23 Continue,
24 Break,
25}
26
27impl ControlFlow {
28 #[inline]
29 #[must_use]
30 pub fn and_then(self, f: impl FnOnce() -> Self) -> Self {
31 match self {
32 Self::Continue => f(),
33 Self::Break => Self::Break,
34 }
35 }
36}
37
38pub struct Once<F, Context, Outcome> {
42 query: Option<F>,
43 result: Option<Outcome>,
44 context: PhantomData<Context>,
45}
46
47impl<F, Context, Outcome> From<Once<F, Context, Outcome>> for Result<Outcome, Error> {
48 #[inline]
49 fn from(query: Once<F, Context, Outcome>) -> Self {
50 query.result.ok_or(Error::ContextTypeMismatch)
51 }
52}
53
54impl<F, ConnectionContext, Outcome> Once<F, ConnectionContext, Outcome>
55where
56 F: FnOnce(&ConnectionContext) -> Outcome,
57 ConnectionContext: 'static,
58{
59 #[inline]
60 pub fn new(query: F) -> Self {
61 Self {
62 query: Some(query),
63 result: None,
64 context: PhantomData,
65 }
66 }
67}
68
69impl<F, ConnectionContext, Outcome> Once<F, ConnectionContext, Outcome>
70where
71 F: FnOnce(&mut ConnectionContext) -> Outcome,
72 ConnectionContext: 'static,
73{
74 #[inline]
75 pub fn new_mut(query: F) -> Self {
76 Self {
77 query: Some(query),
78 result: None,
79 context: PhantomData,
80 }
81 }
82}
83
84impl<F, Context, Outcome> Query for Once<F, Context, Outcome>
85where
86 F: FnOnce(&Context) -> Outcome,
87 Context: 'static,
88{
89 fn execute(&mut self, context: &dyn core::any::Any) -> ControlFlow {
90 match context.downcast_ref::<Context>() {
91 Some(context) => {
92 let query = self.query.take().expect("can only match once");
93 self.result = Some(query(context));
94 ControlFlow::Break
95 }
96 None => ControlFlow::Continue,
97 }
98 }
99}
100
101impl<F, Context, Outcome> QueryMut for Once<F, Context, Outcome>
102where
103 F: FnOnce(&mut Context) -> Outcome,
104 Context: 'static,
105{
106 fn execute_mut(&mut self, context: &mut dyn core::any::Any) -> ControlFlow {
107 match context.downcast_mut::<Context>() {
108 Some(context) => {
109 let query = self.query.take().expect("can only match once");
110 self.result = Some(query(context));
111 ControlFlow::Break
112 }
113 None => ControlFlow::Continue,
114 }
115 }
116}
117
118#[non_exhaustive]
119#[derive(Debug, Clone)]
120pub enum Error {
122 ConnectionLockPoisoned,
124
125 ContextTypeMismatch,
127}
128
129impl core::fmt::Display for Error {
130 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
131 write!(f, "{self:?}")
132 }
133}
134
135#[cfg(feature = "std")]
136impl std::error::Error for Error {}