1use std::future::Future;
65
66use dioform::{IntentSubmitBinding, SubmissionSnapshot, SubmitBinding, SubmitErrors, SubmitResult};
67use dioxus_core::Event;
68
69#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
75pub enum ServerSubmitOutcome<Rejection> {
76 Accepted,
78 Rejected(Rejection),
80}
81
82impl<Rejection> ServerSubmitOutcome<Rejection> {
83 pub const fn accepted() -> Self {
85 Self::Accepted
86 }
87
88 pub const fn rejected(rejection: Rejection) -> Self {
90 Self::Rejected(rejection)
91 }
92}
93
94impl<Success, Rejection> From<Result<Success, Rejection>> for ServerSubmitOutcome<Rejection> {
95 fn from(value: Result<Success, Rejection>) -> Self {
96 match value {
97 Ok(_) => Self::Accepted,
98 Err(rejection) => Self::Rejected(rejection),
99 }
100 }
101}
102
103fn map_server_submit_result<Model, Error, Outcome, Rejection, Failure, MapRejection, MapFailure>(
104 result: Result<Outcome, Failure>,
105 map_rejection: MapRejection,
106 map_failure: MapFailure,
107) -> SubmitErrors<Model, Error>
108where
109 Outcome: Into<ServerSubmitOutcome<Rejection>>,
110 MapRejection: FnOnce(Rejection) -> SubmitErrors<Model, Error>,
111 MapFailure: FnOnce(Failure) -> SubmitErrors<Model, Error>,
112{
113 match result {
114 Ok(outcome) => match outcome.into() {
115 ServerSubmitOutcome::Accepted => SubmitErrors::none(),
116 ServerSubmitOutcome::Rejected(rejection) => map_rejection(rejection),
117 },
118 Err(failure) => map_failure(failure),
119 }
120}
121
122pub trait SubmitBindingFullstackExt<Model, Error> {
124 fn on_submit_server_fn<
127 EventData,
128 Call,
129 Fut,
130 Outcome,
131 Rejection,
132 Failure,
133 MapRejection,
134 MapFailure,
135 >(
136 &self,
137 event: Event<EventData>,
138 call: Call,
139 map_rejection: MapRejection,
140 map_failure: MapFailure,
141 ) -> SubmitResult
142 where
143 EventData: ?Sized + 'static,
144 Call: FnOnce(SubmissionSnapshot<Model>) -> Fut + 'static,
145 Fut: Future<Output = Result<Outcome, Failure>> + 'static,
146 Outcome: Into<ServerSubmitOutcome<Rejection>> + 'static,
147 MapRejection: FnOnce(Rejection) -> SubmitErrors<Model, Error> + 'static,
148 MapFailure: FnOnce(Failure) -> SubmitErrors<Model, Error> + 'static,
149 Model: 'static,
150 Error: 'static;
151}
152
153impl<Model, Error> SubmitBindingFullstackExt<Model, Error> for SubmitBinding<Model, Error>
154where
155 Model: Clone + 'static,
156 Error: 'static,
157{
158 fn on_submit_server_fn<
159 EventData,
160 Call,
161 Fut,
162 Outcome,
163 Rejection,
164 Failure,
165 MapRejection,
166 MapFailure,
167 >(
168 &self,
169 event: Event<EventData>,
170 call: Call,
171 map_rejection: MapRejection,
172 map_failure: MapFailure,
173 ) -> SubmitResult
174 where
175 EventData: ?Sized + 'static,
176 Call: FnOnce(SubmissionSnapshot<Model>) -> Fut + 'static,
177 Fut: Future<Output = Result<Outcome, Failure>> + 'static,
178 Outcome: Into<ServerSubmitOutcome<Rejection>> + 'static,
179 MapRejection: FnOnce(Rejection) -> SubmitErrors<Model, Error> + 'static,
180 MapFailure: FnOnce(Failure) -> SubmitErrors<Model, Error> + 'static,
181 {
182 self.on_submit_async(event, move |submitted| async move {
183 map_server_submit_result(call(submitted).await, map_rejection, map_failure)
184 })
185 }
186}
187
188pub trait IntentSubmitBindingFullstackExt<Model, Intent, Error> {
190 fn on_submit_server_fn<
193 EventData,
194 Call,
195 Fut,
196 Outcome,
197 Rejection,
198 Failure,
199 MapRejection,
200 MapFailure,
201 >(
202 &self,
203 event: Event<EventData>,
204 call: Call,
205 map_rejection: MapRejection,
206 map_failure: MapFailure,
207 ) -> SubmitResult
208 where
209 EventData: ?Sized + 'static,
210 Call: FnOnce(SubmissionSnapshot<Model, Intent>) -> Fut + 'static,
211 Fut: Future<Output = Result<Outcome, Failure>> + 'static,
212 Outcome: Into<ServerSubmitOutcome<Rejection>> + 'static,
213 MapRejection: FnOnce(Rejection) -> SubmitErrors<Model, Error> + 'static,
214 MapFailure: FnOnce(Failure) -> SubmitErrors<Model, Error> + 'static,
215 Model: 'static,
216 Intent: 'static,
217 Error: 'static;
218}
219
220impl<Model, Intent, Error> IntentSubmitBindingFullstackExt<Model, Intent, Error>
221 for IntentSubmitBinding<Model, Intent, Error>
222where
223 Model: Clone + 'static,
224 Intent: Clone + PartialEq + 'static,
225 Error: 'static,
226{
227 fn on_submit_server_fn<
228 EventData,
229 Call,
230 Fut,
231 Outcome,
232 Rejection,
233 Failure,
234 MapRejection,
235 MapFailure,
236 >(
237 &self,
238 event: Event<EventData>,
239 call: Call,
240 map_rejection: MapRejection,
241 map_failure: MapFailure,
242 ) -> SubmitResult
243 where
244 EventData: ?Sized + 'static,
245 Call: FnOnce(SubmissionSnapshot<Model, Intent>) -> Fut + 'static,
246 Fut: Future<Output = Result<Outcome, Failure>> + 'static,
247 Outcome: Into<ServerSubmitOutcome<Rejection>> + 'static,
248 MapRejection: FnOnce(Rejection) -> SubmitErrors<Model, Error> + 'static,
249 MapFailure: FnOnce(Failure) -> SubmitErrors<Model, Error> + 'static,
250 {
251 self.on_submit_async(event, move |submitted| async move {
252 map_server_submit_result(call(submitted).await, map_rejection, map_failure)
253 })
254 }
255}