1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::marker::PhantomData;
7use use_check::{CheckResult, check};
8
9pub mod prelude;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct RuleEvaluation<'a> {
13 name: &'a str,
14 result: CheckResult,
15}
16
17impl<'a> RuleEvaluation<'a> {
18 #[must_use]
19 pub const fn name(&self) -> &'a str {
20 self.name
21 }
22
23 #[must_use]
24 pub const fn result(&self) -> CheckResult {
25 self.result
26 }
27
28 #[must_use]
29 pub const fn passed(&self) -> bool {
30 self.result.is_pass()
31 }
32}
33
34pub struct Rule<T: ?Sized, F> {
35 name: &'static str,
36 checker: F,
37 marker: PhantomData<fn(&T)>,
38}
39
40impl<T: ?Sized, F> Rule<T, F>
41where
42 F: Fn(&T) -> bool,
43{
44 #[must_use]
45 pub const fn new(name: &'static str, checker: F) -> Self {
46 Self {
47 name,
48 checker,
49 marker: PhantomData,
50 }
51 }
52
53 #[must_use]
54 pub const fn name(&self) -> &'static str {
55 self.name
56 }
57
58 #[must_use]
59 pub fn evaluate(&self, value: &T) -> RuleEvaluation<'static> {
60 RuleEvaluation {
61 name: self.name,
62 result: check((self.checker)(value)),
63 }
64 }
65
66 #[must_use]
67 pub fn passes(&self, value: &T) -> bool {
68 self.evaluate(value).passed()
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::Rule;
75
76 #[test]
77 fn rules_keep_a_name_and_result() {
78 let rule = Rule::<i32, _>::new("positive", |value| *value > 0);
79 let evaluation = rule.evaluate(&42);
80
81 assert_eq!(evaluation.name(), "positive");
82 assert!(evaluation.passed());
83 }
84}