1use {
5 crate::{One, Sigma, Test, Zero},
6 core::{cmp::Ordering, fmt, marker::PhantomData},
7};
8
9#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
11pub struct NotOnUnit<
12 'i,
13 Input: One + PartialOrd + Zero + fmt::Debug,
14 const INCLUSIVE_AT_ZERO: bool,
15 const INCLUSIVE_AT_ONE: bool,
16>(&'i Input);
17
18impl<
19 Input: One + PartialOrd + Zero + fmt::Debug,
20 const INCLUSIVE_AT_ZERO: bool,
21 const INCLUSIVE_AT_ONE: bool,
22> fmt::Display for NotOnUnit<'_, Input, INCLUSIVE_AT_ZERO, INCLUSIVE_AT_ONE>
23{
24 #[inline]
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 #![expect(
27 clippy::use_debug,
28 reason = "Intentional and informative, not just forgotten print-debugging"
29 )]
30
31 let Self(u) = *self;
32 write!(
33 f,
34 "Not on {}0, 1{}: {u:#?}",
35 if INCLUSIVE_AT_ZERO { '[' } else { '(' },
36 if INCLUSIVE_AT_ONE { ']' } else { ')' },
37 )
38 }
39}
40
41pub type OnUnit<Input, const INCLUSIVE_AT_ZERO: bool, const INCLUSIVE_AT_ONE: bool> =
44 Sigma<Input, OnUnitInvariant<Input, INCLUSIVE_AT_ZERO, INCLUSIVE_AT_ONE>>;
45
46#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
49pub struct OnUnitInvariant<
50 Input: One + PartialOrd + Zero + fmt::Debug,
51 const INCLUSIVE_AT_ZERO: bool,
52 const INCLUSIVE_AT_ONE: bool,
53>(PhantomData<Input>);
54
55impl<
56 Input: One + PartialOrd + Zero + fmt::Debug,
57 const INCLUSIVE_AT_ZERO: bool,
58 const INCLUSIVE_AT_ONE: bool,
59> Test<Input, 1> for OnUnitInvariant<Input, INCLUSIVE_AT_ZERO, INCLUSIVE_AT_ONE>
60{
61 const ADJECTIVE: &str = "on the unit interval";
62 type Error<'i>
63 = NotOnUnit<'i, Input, INCLUSIVE_AT_ZERO, INCLUSIVE_AT_ONE>
64 where
65 Input: 'i;
66
67 #[inline]
68 fn test([input]: [&Input; 1]) -> Result<(), Self::Error<'_>> {
69 match input.partial_cmp(&Input::ZERO) {
70 None | Some(Ordering::Less) => return Err(NotOnUnit(input)),
71 Some(Ordering::Equal) => {
72 if !INCLUSIVE_AT_ZERO {
73 return Err(NotOnUnit(input));
74 }
75 }
76 Some(Ordering::Greater) => {}
77 }
78 match input.partial_cmp(&Input::ONE) {
79 None | Some(Ordering::Greater) => return Err(NotOnUnit(input)),
80 Some(Ordering::Equal) => {
81 if !INCLUSIVE_AT_ONE {
82 return Err(NotOnUnit(input));
83 }
84 }
85 Some(Ordering::Less) => {}
86 }
87 Ok(())
88 }
89}