Skip to content

Commit 629cde4

Browse files
committed
Make predicates inconstructible.
1 parent 8dd1e0f commit 629cde4

File tree

11 files changed

+114
-98
lines changed

11 files changed

+114
-98
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ use refinement_types::{Refinement, int::u8, length, logic::And, str};
4848
pub type Name<'n> = Refinement<&'n str, And<str::Ascii, length::Closed<1, 32>>>;
4949

5050
/// Represents device charge, in percentage.
51-
pub type Charge = Refinement<u8, u8::Closed<1, 100>>;
51+
pub type Charge = Refinement<u8, u8::LessOrEqual<100>>;
5252

5353
/// Represents devices.
5454
#[derive(Debug)]
@@ -83,8 +83,8 @@ impl<'d> Device<'d> {
8383
```rust
8484
// main.rs
8585

86-
use anyhow::Result;
8786
use device::{Charge, Device, Name};
87+
use miette::Result;
8888

8989
fn main() -> Result<()> {
9090
let charge = Charge::refine(13)?;

src/char/ascii.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! ASCII character predicates.
22
3-
use core::fmt;
3+
use core::{fmt, marker::PhantomData};
44

55
#[cfg(feature = "diagnostics")]
66
use miette::Diagnostic;
@@ -39,8 +39,9 @@ impl DigitError {
3939
}
4040

4141
/// Checks whether the given character is a digit in the specified base `B`.
42-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
43-
pub struct Digit<const B: Base = 10>;
42+
pub struct Digit<const B: Base = 10> {
43+
private: PhantomData<()>,
44+
}
4445

4546
/// Checks whether the given character is an octal digit.
4647
pub type OctDigit = Digit<8>;

src/char/macros.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pub(crate) mod import {
2-
pub use core::fmt;
2+
pub use core::{fmt, marker::PhantomData};
33

44
pub use paste::paste;
55
pub use thiserror::Error;
@@ -37,9 +37,10 @@ macro_rules! predicate {
3737
}
3838
}
3939

40-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
4140
#[doc = $doc]
42-
pub struct $name;
41+
pub struct $name {
42+
private: $crate::char::macros::import::PhantomData<()>,
43+
}
4344

4445
impl $crate::core::Predicate<char> for $name {
4546
type Error = [< $name Error >];

src/core.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,12 @@ pub trait Predicate<T: ?Sized> {
8686
}
8787

8888
/// Represents expectations of predicates.
89-
pub struct Expected<T: ?Sized, P: Predicate<T> + ?Sized> {
89+
pub struct Expected<T: ?Sized, P: ?Sized> {
9090
value: PhantomData<T>,
9191
predicate: PhantomData<P>,
9292
}
9393

94-
impl<T: ?Sized, P: Predicate<T> + ?Sized> Expected<T, P> {
94+
impl<T: ?Sized, P: ?Sized> Expected<T, P> {
9595
const fn new() -> Self {
9696
Self {
9797
value: PhantomData,
@@ -107,12 +107,12 @@ impl<T: ?Sized, P: Predicate<T> + ?Sized> fmt::Display for Expected<T, P> {
107107
}
108108

109109
/// Represents expectation codes of predicates.
110-
pub struct ExpectedCode<T: ?Sized, P: Predicate<T> + ?Sized> {
110+
pub struct ExpectedCode<T: ?Sized, P: ?Sized> {
111111
value: PhantomData<T>,
112112
predicate: PhantomData<P>,
113113
}
114114

115-
impl<T: ?Sized, P: Predicate<T> + ?Sized> ExpectedCode<T, P> {
115+
impl<T: ?Sized, P: ?Sized> ExpectedCode<T, P> {
116116
const fn new() -> Self {
117117
Self {
118118
value: PhantomData,
@@ -413,6 +413,16 @@ impl<T, P: Predicate<T> + ?Sized, H: TypeStr + ?Sized> Refinement<T, P, H> {
413413
Self::refine(function(self.take()))
414414
}
415415

416+
/// Maps thte value of the refinement without checking the new value.
417+
///
418+
/// # Safety
419+
///
420+
/// The caller must ensure that the new value satisfies the predicate.
421+
pub unsafe fn map_unchecked<F: FnOnce(T) -> T>(self, function: F) -> Self {
422+
// SAFETY: the caller must ensure that the new value satisfies the predicate
423+
unsafe { Self::unchecked(function(self.take())) }
424+
}
425+
416426
/// Replaces the value of the refinement.
417427
///
418428
/// # Errors
@@ -422,6 +432,16 @@ impl<T, P: Predicate<T> + ?Sized, H: TypeStr + ?Sized> Refinement<T, P, H> {
422432
Self::refine(value)
423433
}
424434

435+
/// Replaces the value of the refinement without checking the new value.
436+
///
437+
/// # Safety
438+
///
439+
/// The caller must ensure that the new value satisfies the predicate.
440+
pub unsafe fn replace_unchecked(self, value: T) -> Self {
441+
// SAFETY: the caller must ensure that the new value satisfies the predicate
442+
unsafe { Self::unchecked(value) }
443+
}
444+
425445
#[cfg(feature = "unsafe-assert")]
426446
fn assert_refined(&self) {
427447
unsafe { assert_unchecked(Self::is_fine(&self.value)) }
@@ -436,7 +456,7 @@ impl<T, P: Predicate<T> + ?Sized, H: TypeStr + ?Sized> Refinement<T, P, H> {
436456
}
437457

438458
/// Returns a reference to the value of the refinement.
439-
#[allow(clippy::missing_const_for_fn)]
459+
#[allow(clippy::missing_const_for_fn)] // conditionally const
440460
pub fn get(&self) -> &T {
441461
#[cfg(feature = "unsafe-assert")]
442462
self.assert_refined();

src/empty.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Predicates based on emptiness.
22
33
use core::fmt;
4+
use core::marker::PhantomData;
45

56
use thiserror::Error;
67

@@ -31,8 +32,9 @@ pub const VALUE: StaticStr = "empty value";
3132
pub const EMPTY: StaticStr = "empty";
3233

3334
/// Checks whether the value is empty.
34-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
35-
pub struct Empty;
35+
pub struct Empty {
36+
private: PhantomData<()>,
37+
}
3638

3739
impl<T: HasEmpty + ?Sized> Predicate<T> for Empty {
3840
type Error = EmptyError;

src/int/macros.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pub(crate) mod import {
2-
pub use core::fmt;
2+
pub use core::{fmt, marker::PhantomData};
33

44
pub use paste::paste;
55
pub use thiserror::Error;
@@ -129,8 +129,9 @@ macro_rules! compare {
129129
$crate::int::macros::human!($operation),
130130
" `N`."
131131
)]
132-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
133-
pub struct $name<const N: $int>;
132+
pub struct $name<const N: $int> {
133+
private: $crate::int::macros::import::PhantomData<()>,
134+
}
134135

135136
impl<const N: $int> $crate::core::Predicate<$int> for $name<N> {
136137
type Error = [< $name Error >];
@@ -313,7 +314,7 @@ macro_rules! modulo {
313314
feature = "diagnostics",
314315
derive($crate::int::macros::import::Diagnostic),
315316
diagnostic(
316-
code(int::$int::Modulo),
317+
code(int::$int::modulo),
317318
help("make sure the value divided by {divisor} and has modulo {modulo}")
318319
)
319320
)]
@@ -334,8 +335,9 @@ macro_rules! modulo {
334335
#[doc = concat!(
335336
"Checks whether ", $crate::int::macros::reference!($int), " divided by `D` has modulo `M`."
336337
)]
337-
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
338-
pub struct Modulo<const D: $int, const M: $int>;
338+
pub struct Modulo<const D: $int, const M: $int> {
339+
private: $crate::int::macros::import::PhantomData<()>,
340+
}
339341

340342
impl<const D: $int, const M: $int> $crate::core::Predicate<$int> for Modulo<D, M> {
341343
type Error = ModuloError;

src/length.rs

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Predicates based on length.
22
3-
use core::fmt;
3+
use core::{fmt, marker::PhantomData};
44

55
#[cfg(feature = "diagnostics")]
66
use miette::Diagnostic;
@@ -40,8 +40,9 @@ impl LessError {
4040
}
4141

4242
/// Checks whether the given value has length less than `N`.
43-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
44-
pub struct Less<const N: usize>;
43+
pub struct Less<const N: usize> {
44+
private: PhantomData<()>,
45+
}
4546

4647
impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for Less<N> {
4748
type Error = LessError;
@@ -88,8 +89,9 @@ impl LessOrEqualError {
8889
}
8990

9091
/// Checks whether the given value has length less than or equal to `N`.
91-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
92-
pub struct LessOrEqual<const N: usize>;
92+
pub struct LessOrEqual<const N: usize> {
93+
private: PhantomData<()>,
94+
}
9395

9496
impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for LessOrEqual<N> {
9597
type Error = LessOrEqualError;
@@ -133,8 +135,9 @@ impl GreaterError {
133135
}
134136

135137
/// Checks whether the given value has length greater than `N`.
136-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
137-
pub struct Greater<const N: usize>;
138+
pub struct Greater<const N: usize> {
139+
private: PhantomData<()>,
140+
}
138141

139142
impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for Greater<N> {
140143
type Error = GreaterError;
@@ -181,8 +184,9 @@ impl GreaterOrEqualError {
181184
}
182185

183186
/// Checks whether the given value has length greater than or equal to `N`.
184-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
185-
pub struct GreaterOrEqual<const N: usize>;
187+
pub struct GreaterOrEqual<const N: usize> {
188+
private: PhantomData<()>,
189+
}
186190

187191
impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for GreaterOrEqual<N> {
188192
type Error = GreaterOrEqualError;
@@ -226,8 +230,9 @@ impl EqualError {
226230
}
227231

228232
/// Checks whether the given value has length equal to `N`.
229-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
230-
pub struct Equal<const N: usize>;
233+
pub struct Equal<const N: usize> {
234+
private: PhantomData<()>,
235+
}
231236

232237
impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for Equal<N> {
233238
type Error = EqualError;
@@ -271,8 +276,9 @@ impl NotEqualError {
271276
}
272277

273278
/// Checks whether the given value has length not equal to `N`.
274-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
275-
pub struct NotEqual<const N: usize>;
279+
pub struct NotEqual<const N: usize> {
280+
private: PhantomData<()>,
281+
}
276282

277283
impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for NotEqual<N> {
278284
type Error = NotEqualError;
@@ -335,8 +341,9 @@ impl ModuloError {
335341
}
336342

337343
/// Checks whether the given value length divided by `D` has modulo `M`.
338-
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
339-
pub struct Modulo<const D: usize, const M: usize>;
344+
pub struct Modulo<const D: usize, const M: usize> {
345+
private: PhantomData<()>,
346+
}
340347

341348
impl<const D: usize, const M: usize, T: HasLength + ?Sized> Predicate<T> for Modulo<D, M> {
342349
type Error = ModuloError;

src/logic.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ use crate::{
1313
};
1414

1515
/// Represents predicates that are always satisfied.
16-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
17-
pub struct True;
16+
pub struct True {
17+
private: PhantomData<()>,
18+
}
1819

1920
/// Represents errors that are never encountered.
2021
///
@@ -51,8 +52,9 @@ impl<T: ?Sized> Predicate<T> for True {
5152
}
5253

5354
/// Represents predicates that are never satisfied.
54-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
55-
pub struct False;
55+
pub struct False {
56+
private: PhantomData<()>,
57+
}
5658

5759
/// Represents errors that are always encountered.
5860
#[derive(Debug, Error)]
@@ -132,7 +134,6 @@ impl<E: Diagnostic + 'static, F: Diagnostic + 'static> Diagnostic for EitherErro
132134
}
133135

134136
/// Represents predicates that are satisfied when both `P` and `Q` are satisfied.
135-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
136137
pub struct And<P: ?Sized, Q: ?Sized> {
137138
left: PhantomData<P>,
138139
right: PhantomData<Q>,
@@ -143,8 +144,8 @@ impl<T: ?Sized, P: Predicate<T> + ?Sized, Q: Predicate<T> + ?Sized> Predicate<T>
143144

144145
fn check(value: &T) -> Result<(), Self::Error> {
145146
P::check(value)
146-
.map_err(EitherError::Left)
147-
.and_then(|()| Q::check(value).map_err(EitherError::Right))
147+
.map_err(Self::Error::Left)
148+
.and_then(|()| Q::check(value).map_err(Self::Error::Right))
148149
}
149150

150151
fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -202,7 +203,6 @@ impl<E: Diagnostic, F: Diagnostic> Diagnostic for BothError<E, F> {
202203
}
203204

204205
/// Represents predicates that are satisfied when either `P` or `Q` (or both) are satisfied.
205-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
206206
pub struct Or<P: ?Sized, Q: ?Sized> {
207207
left: PhantomData<P>,
208208
right: PhantomData<Q>,
@@ -248,7 +248,6 @@ impl NotError {
248248
}
249249

250250
/// Represents predicates that are satisfied when `P` is not satisfied.
251-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
252251
pub struct Not<P: ?Sized> {
253252
predicate: PhantomData<P>,
254253
}
@@ -318,7 +317,6 @@ impl<E: Diagnostic + 'static, F: Diagnostic + 'static> Diagnostic for NeitherOrB
318317
}
319318

320319
/// Represents predicates that are satisfied when either `P` or `Q` (but *not* both) are satisfied.
321-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
322320
pub struct Xor<P: ?Sized, Q: ?Sized> {
323321
left: PhantomData<P>,
324322
right: PhantomData<Q>,

0 commit comments

Comments
 (0)