1use std::{
6 borrow::Borrow,
7 fmt::{Debug, Display},
8 hash::Hash,
9 marker::PhantomData,
10 ops::Deref,
11 str::FromStr,
12};
13
14use frunk_core::HList;
15
16use crate::{
17 inference_rule::{
18 AuthorizedInferenceRuleGhost, InferenceRule, Operation, PreservingTransformGhost,
19 },
20 predicate::{
21 impl_::all_of::AllOf, AsyncEvaluablePredicate, Predicate, PurePredicate,
22 SyncEvaluablePredicate,
23 },
24};
25
26pub struct Proven<S, P> {
28 subject: S,
30
31 _gdp: PhantomData<P>,
33}
34
35#[cfg(feature = "serde")]
36impl<Sub, P> serde::Serialize for Proven<Sub, P>
37where
38 Sub: serde::Serialize,
39{
40 #[inline]
41 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
42 where
43 S: serde::Serializer,
44 {
45 self.subject.serialize(serializer)
46 }
47}
48
49#[cfg(feature = "serde")]
52pub struct ExpectedProven<S, P> {
53 _phantom: PhantomData<fn() -> (S, P)>,
54}
55
56#[cfg(feature = "serde")]
57impl<S, P: Predicate<S>> serde::de::Expected for ExpectedProven<S, P> {
58 fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
59 write!(
60 formatter,
61 "a subject value that satisfies {} predicate evaluation",
62 P::label().as_ref()
63 )
64 }
65}
66
67#[cfg(feature = "serde")]
68impl<'de, Sub, P> serde::Deserialize<'de> for Proven<Sub, P>
69where
70 Sub: serde::Deserialize<'de>,
71 P: SyncEvaluablePredicate<Sub>,
72{
73 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
74 where
75 D: serde::Deserializer<'de>,
76 {
77 let subject = Sub::deserialize(deserializer)?;
78 Proven::try_new(subject).map_err(|_| {
79 <D::Error as serde::de::Error>::invalid_value(
80 serde::de::Unexpected::Other("predicate evaluation failing subject"),
81 &ExpectedProven::<Sub, P> {
82 _phantom: PhantomData,
83 },
84 )
85 })
86 }
87}
88
89impl<S, P> Hash for Proven<S, P>
90where
91 S: Hash,
92 P: PurePredicate<S>,
93{
94 #[inline]
95 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
96 self.subject.hash(state);
97 }
98}
99
100impl<S, P> Ord for Proven<S, P>
101where
102 S: Ord,
103 P: PurePredicate<S>,
104{
105 #[inline]
106 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
107 self.subject.cmp(&other.subject)
108 }
109}
110
111impl<S, P> PartialOrd for Proven<S, P>
112where
113 S: PartialOrd,
114 P: PurePredicate<S>,
115{
116 #[inline]
117 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
118 self.subject.partial_cmp(&other.subject)
119 }
120}
121
122impl<S, P> Eq for Proven<S, P>
123where
124 S: Eq,
125 P: PurePredicate<S>,
126{
127}
128
129impl<S, P> PartialEq for Proven<S, P>
130where
131 S: PartialEq,
132 P: PurePredicate<S>,
133{
134 #[inline]
135 fn eq(&self, other: &Self) -> bool {
136 self.subject == other.subject
137 }
138}
139
140impl<S, P> Copy for Proven<S, P>
141where
142 S: Copy,
143 P: PurePredicate<S>,
144{
145}
146
147impl<S, P> Clone for Proven<S, P>
148where
149 S: Clone,
150 P: PurePredicate<S>,
151{
152 #[inline]
153 fn clone(&self) -> Self {
154 Self {
155 subject: self.subject.clone(),
156 _gdp: PhantomData,
157 }
158 }
159}
160
161impl<S, P> Debug for Proven<S, P>
162where
163 S: Debug,
164 P: Predicate<S>,
165{
166 #[inline]
167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168 write!(f, "Proven<{}>({:?})", P::label(), self.subject)
169 }
170}
171
172impl<S, P> Display for Proven<S, P>
173where
174 S: Display,
175 P: Predicate<S>,
176{
177 #[inline]
178 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179 self.subject.fmt(f)
180 }
181}
182
183impl<S, P> AsRef<S> for Proven<S, P> {
184 #[inline]
185 fn as_ref(&self) -> &S {
186 &self.subject
187 }
188}
189
190impl<S, P> Deref for Proven<S, P> {
191 type Target = S;
192
193 #[inline]
194 fn deref(&self) -> &Self::Target {
195 &self.subject
196 }
197}
198
199impl<S, P> Borrow<S> for Proven<S, P> {
200 #[inline]
201 fn borrow(&self) -> &S {
202 &self.subject
203 }
204}
205
206impl<S, P> Proven<S, P>
207where
208 P: Predicate<S>,
209{
210 #[inline]
212 pub fn into_subject(self) -> S {
213 self.subject
214 }
215
216 pub fn subject_into<T>(self) -> Proven<T, P>
218 where
219 P: Predicate<T>,
220 S: Into<T>,
221 {
222 Proven {
223 subject: self.subject.into(),
224 _gdp: PhantomData,
225 }
226 }
227
228 #[inline]
234 pub const unsafe fn new_unchecked(subject: S) -> Self {
235 Self {
236 subject,
237 _gdp: PhantomData,
238 }
239 }
240
241 pub fn transform_sub<Op: Operation<Arg = S, Result = S> + PreservingTransformGhost<P, S>>(
243 self,
244 op: Op,
245 ) -> Proven<S, P> {
246 Proven {
247 subject: op.call(self.subject),
248 _gdp: PhantomData,
249 }
250 }
251
252 #[inline]
254 pub fn infer<R>(self, op: R::SubjectTransform) -> Proven<R::TargetSub, R::TargetPredicate>
255 where
256 R: InferenceRule<SourceSub = S, SourcePredicate = P>,
257 PhantomData<R>: AuthorizedInferenceRuleGhost<R::TargetPredicate, R::TargetSub>,
258 {
259 Proven {
260 subject: op.call(self.subject),
261 _gdp: PhantomData,
262 }
263 }
264
265 #[inline]
268 #[allow(clippy::type_complexity)]
269 pub fn and_infer<R>(
270 self,
271 op: R::SubjectTransform,
272 ) -> Proven<R::TargetSub, AllOf<S, HList!(R::TargetPredicate, P)>>
273 where
274 R: InferenceRule<SourceSub = S, TargetSub = S, SourcePredicate = P>,
275 PhantomData<R::SubjectTransform>: PreservingTransformGhost<P, S>,
276 PhantomData<R>: AuthorizedInferenceRuleGhost<R::TargetPredicate, S>,
277 {
278 Proven {
279 subject: op.call(self.subject),
280 _gdp: PhantomData,
281 }
282 }
283}
284
285impl<S, P> Proven<S, P>
286where
287 P: Predicate<S>,
288{
289 pub fn try_new(subject: S) -> Result<Self, ProvenError<S, P::EvalError>>
291 where
292 P: SyncEvaluablePredicate<S>,
293 {
294 match P::evaluate_for(&subject) {
295 Ok(_) => Ok(Self {
296 subject,
297 _gdp: PhantomData,
298 }),
299 Err(e) => Err(ProvenError { error: e, subject }),
300 }
301 }
302
303 pub async fn try_new_async(subject: S) -> Result<Self, ProvenError<S, P::EvalError>>
305 where
306 P: AsyncEvaluablePredicate<S>,
307 {
308 match P::evaluate_for(&subject).await {
309 Ok(_) => Ok(Self {
310 subject,
311 _gdp: PhantomData,
312 }),
313 Err(e) => Err(ProvenError { error: e, subject }),
314 }
315 }
316
317 #[allow(clippy::type_complexity)]
319 pub fn try_new_from<V>(
320 subject: V,
321 ) -> Result<Self, ConvertOrProvenError<<S as TryFrom<V>>::Error, S, P::EvalError>>
322 where
323 S: TryFrom<V> + TryProven<P, Err = ProvenError<S, P::EvalError>> + Sized,
324 P: SyncEvaluablePredicate<S>,
325 {
326 TryInto::<S>::try_into(subject)
327 .map_err(ConvertOrProvenError::ConvertError)?
328 .try_proven()
329 .map_err(ConvertOrProvenError::ProvenError)
330 }
331}
332
333pub trait TryProven<P>: Sized {
335 type Err: Debug;
337
338 fn try_proven(self) -> Result<Proven<Self, P>, Self::Err>;
340}
341
342impl<S, P> TryProven<P> for S
343where
344 S: Sized,
345 P: Predicate<S> + SyncEvaluablePredicate<S>,
346{
347 type Err = ProvenError<S, P::EvalError>;
348
349 #[inline]
350 fn try_proven(self) -> Result<Proven<Self, P>, Self::Err> {
351 Proven::try_new(self)
352 }
353}
354
355impl<S, P> FromStr for Proven<S, P>
356where
357 S: FromStr,
358 P: Predicate<S> + SyncEvaluablePredicate<S>,
359{
360 type Err = ConvertOrProvenError<S::Err, S, P::EvalError>;
361
362 fn from_str(s: &str) -> Result<Self, Self::Err> {
363 S::from_str(s)
364 .map_err(ConvertOrProvenError::ConvertError)?
365 .try_proven()
366 .map_err(ConvertOrProvenError::ProvenError)
367 }
368}
369
370#[derive(thiserror::Error)]
372#[error("Error in proving predicate about subject. Error: {error}")]
373pub struct ProvenError<S, PErr> {
374 pub subject: S,
376
377 pub error: PErr,
379}
380
381impl<S, PErr: Debug> Debug for ProvenError<S, PErr> {
382 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
383 f.debug_struct("ProvenError")
384 .field("error", &self.error)
385 .finish()
387 }
388}
389
390impl<S, PErr> ProvenError<S, PErr> {
391 #[inline]
393 pub fn into_parts(self) -> (S, PErr) {
394 (self.subject, self.error)
395 }
396
397 #[inline]
399 pub fn subject(&self) -> &S {
400 &self.subject
401 }
402
403 #[inline]
405 pub fn error(&self) -> &PErr {
406 &self.error
407 }
408}
409#[derive(thiserror::Error)]
412pub enum ConvertOrProvenError<C, S, PErr: Display> {
413 #[error("Error in conversion. Error: {0}")]
415 ConvertError(C),
416
417 #[error("Error in proving the predicate about converted subject. Error: {0}")]
419 ProvenError(ProvenError<S, PErr>),
420}
421
422impl<C, S, PErr: Debug + Display> Debug for ConvertOrProvenError<C, S, PErr> {
423 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
424 match self {
425 Self::ConvertError(_) => f.debug_tuple("ConvertError").finish(),
426 Self::ProvenError(e) => f.debug_tuple("ProvenError").field(e).finish(),
427 }
428 }
429}