1use core::{
4 cmp::Ordering,
5 fmt,
6 hash::{Hash, Hasher},
7 marker::PhantomData,
8 mem::transmute,
9 ops::Deref,
10};
11
12#[cfg(feature = "unsafe-assert")]
13use core::hint::assert_unchecked;
14
15use crate::{
16 context::NoContext,
17 errors::{Error, Recoverable, RecoverableRef},
18 predicate::Predicate,
19 types::TypeStr,
20};
21
22#[repr(transparent)]
24pub struct Refinement<T: ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized = NoContext> {
25 predicate: PhantomData<P>,
26 context: PhantomData<C>,
27 value: T,
28}
29
30impl<T: fmt::Debug + ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> fmt::Debug
31 for Refinement<T, P, C>
32{
33 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
34 self.get_ref().fmt(formatter)
35 }
36}
37
38impl<T: fmt::Display + ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> fmt::Display
39 for Refinement<T, P, C>
40{
41 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
42 self.get_ref().fmt(formatter)
43 }
44}
45
46impl<T: PartialEq + ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> PartialEq
47 for Refinement<T, P, C>
48{
49 fn eq(&self, other: &Self) -> bool {
50 self.get_ref().eq(other.get_ref())
51 }
52}
53
54impl<T: Eq + ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> Eq for Refinement<T, P, C> {}
55
56impl<T: PartialOrd + ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> PartialOrd
57 for Refinement<T, P, C>
58{
59 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
60 self.get_ref().partial_cmp(other.get_ref())
61 }
62}
63
64impl<T: Ord + ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> Ord for Refinement<T, P, C> {
65 fn cmp(&self, other: &Self) -> Ordering {
66 self.get_ref().cmp(other.get_ref())
67 }
68}
69
70impl<T: Hash + ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> Hash for Refinement<T, P, C> {
71 fn hash<H: Hasher>(&self, state: &mut H) {
72 self.get_ref().hash(state);
73 }
74}
75
76impl<T: ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> AsRef<T> for Refinement<T, P, C> {
77 fn as_ref(&self) -> &T {
78 self.get_ref()
79 }
80}
81
82impl<T: ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> Deref for Refinement<T, P, C> {
83 type Target = T;
84
85 fn deref(&self) -> &Self::Target {
86 self.get_ref()
87 }
88}
89
90mod sealed {
91 pub trait Sealed {}
92}
93
94pub type RecoverableRefinement<R> =
96 Recoverable<R, <R as Refining>::Predicate, <R as Refining>::Context, <R as Refining>::Value>;
97
98pub type RecoverableRefinementRef<'a, R> = RecoverableRef<
100 'a,
101 R,
102 <R as Refining>::Predicate,
103 <R as Refining>::Context,
104 <R as Refining>::Value,
105>;
106
107pub trait Refining: Deref<Target = Self::Value> + sealed::Sealed {
111 type Value: ?Sized;
113
114 type Predicate: Predicate<Self::Value> + ?Sized;
116
117 type Context: TypeStr + ?Sized;
119
120 unsafe fn unchecked_ref(value: &Self::Value) -> &Self;
130
131 unsafe fn unchecked(value: Self::Value) -> Self
141 where
142 Self::Value: Sized;
143
144 fn is_fine(value: &Self::Value) -> bool {
150 Self::Predicate::check(value)
151 }
152
153 fn get_ref(&self) -> &Self::Value;
155
156 fn get(self) -> Self::Value
158 where
159 Self::Value: Sized;
160
161 fn checked_ref(value: &Self::Value) -> RecoverableRefinementRef<'_, Self>;
168
169 fn checked(value: Self::Value) -> RecoverableRefinement<Self>
176 where
177 Self::Value: Sized,
178 Self: Sized;
179}
180
181impl<T: ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> Refinement<T, P, C> {
182 pub const unsafe fn unchecked_ref(value: &T) -> &Self {
191 unsafe { transmute(value) }
194 }
195
196 #[allow(clippy::missing_const_for_fn)] pub fn get_ref(&self) -> &T {
207 let reference = self.get_ref_no_assert();
208
209 #[cfg(feature = "unsafe-assert")]
210 unsafe {
211 assert_unchecked(Self::is_fine(reference));
212 }
213
214 reference
215 }
216
217 pub const fn get_ref_no_assert(&self) -> &T {
219 &self.value
220 }
221
222 pub fn is_fine(value: &T) -> bool {
228 P::check(value)
229 }
230
231 pub fn checked_ref(value: &T) -> RecoverableRef<'_, Self, P, C, T> {
239 if Self::is_fine(value) {
240 Ok(unsafe { Self::unchecked_ref(value) })
241 } else {
242 Err(Error::new_ref(value))
243 }
244 }
245}
246
247impl<T, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> Refinement<T, P, C> {
248 pub const unsafe fn unchecked(value: T) -> Self {
257 Self {
258 predicate: PhantomData,
259 context: PhantomData,
260 value,
261 }
262 }
263
264 pub fn get(self) -> T {
274 let value = self.get_no_assert();
275
276 #[cfg(feature = "unsafe-assert")]
277 unsafe {
278 assert_unchecked(Self::is_fine(&value));
279 }
280
281 value
282 }
283
284 pub fn get_no_assert(self) -> T {
286 self.value
287 }
288
289 pub fn checked(value: T) -> Recoverable<Self, P, C, T> {
297 if Self::is_fine(&value) {
298 Ok(unsafe { Self::unchecked(value) })
299 } else {
300 Err(Error::new(value))
301 }
302 }
303}
304
305impl<T: ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> sealed::Sealed
306 for Refinement<T, P, C>
307{
308}
309
310impl<T: ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> Refining for Refinement<T, P, C> {
311 type Value = T;
312 type Predicate = P;
313 type Context = C;
314
315 unsafe fn unchecked_ref(value: &Self::Value) -> &Self {
316 unsafe { Self::unchecked_ref(value) }
317 }
318
319 unsafe fn unchecked(value: Self::Value) -> Self
320 where
321 Self::Value: Sized,
322 {
323 unsafe { Self::unchecked(value) }
324 }
325
326 fn is_fine(value: &Self::Value) -> bool {
327 Self::is_fine(value)
328 }
329
330 fn get_ref(&self) -> &Self::Value {
331 self.get_ref()
332 }
333
334 fn get(self) -> Self::Value
335 where
336 Self::Value: Sized,
337 {
338 self.get()
339 }
340
341 fn checked_ref(value: &Self::Value) -> RecoverableRefinementRef<'_, Self> {
342 Self::checked_ref(value)
343 }
344
345 fn checked(value: Self::Value) -> RecoverableRefinement<Self>
346 where
347 Self::Value: Sized,
348 {
349 Self::checked(value)
350 }
351}
352
353pub trait Refine {
355 fn refine_ref<R: Refining<Value = Self> + ?Sized>(&self) -> RecoverableRefinementRef<'_, R> {
366 R::checked_ref(self)
367 }
368
369 fn refine<R: Refining<Value = Self>>(self) -> RecoverableRefinement<R>
380 where
381 Self: Sized,
382 {
383 R::checked(self)
384 }
385}
386
387impl<T: ?Sized> Refine for T {}