1#![doc = include_str!("../README.md")]
2
3use std::cmp::{Eq, PartialEq};
4use std::marker::PhantomData;
5use std::ops::{Add, Deref, Div, Mul, Sub};
6
7mod base_checked_ops;
10pub use base_checked_ops::*;
11
12#[derive(Debug)]
14pub struct WithDeref;
15
16#[derive(Debug)]
18pub struct WithoutDeref;
19
20#[derive(Debug)]
37pub struct Checked<T, D = WithDeref> {
38 v: T,
39 _deref: PhantomData<D>,
40}
41
42impl<T, D> Clone for Checked<T, D>
43where
44 T: Clone,
45{
46 fn clone(&self) -> Self {
47 Self {
48 v: self.v.clone(),
49 _deref: self._deref,
50 }
51 }
52}
53
54impl<T, D> Copy for Checked<T, D> where T: Copy {}
55
56impl<T, D> From<T> for Checked<T, D> {
57 fn from(v: T) -> Self {
58 Self { v, _deref: PhantomData }
59 }
60}
61
62impl<T, D> Checked<T, D> {
63 pub fn into_inner(self) -> T {
64 self.v
65 }
66}
67
68impl<T, D> Checked<T, D>
69where
70 T: Clone,
71{
72 pub fn to_inner(&self) -> T {
73 self.v.clone()
74 }
75
76}
77
78impl<T> Checked<T, WithDeref> {
79 pub fn new_with_deref(v: T) -> Checked<T, WithDeref> {
80 Self {
81 v,
82 _deref: PhantomData,
83 }
84 }
85
86 pub fn new(v: T) -> Self {
87 Self {
88 v,
89 _deref: PhantomData,
90 }
91 }
92}
93
94impl<T> Checked<T, WithoutDeref> {
95 pub fn new_without_deref(v: T) -> Checked<T, WithoutDeref> {
96 Self {
97 v,
98 _deref: PhantomData,
99 }
100 }
101
102}
103
104impl<T> Deref for Checked<T, WithDeref> {
105 type Target = T;
106
107 fn deref(&self) -> &Self::Target {
108 &self.v
109 }
110}
111
112
113#[derive(Debug)]
120pub struct Unchecked<T, D = WithoutDeref> {
121 v: Option<T>,
122 _deref: PhantomData<D>,
123}
124
125impl<T, D> Clone for Unchecked<T, D>
126where
127 T: Clone,
128{
129 fn clone(&self) -> Self {
130 Self {
131 v: self.v.clone(),
132 _deref: self._deref,
133 }
134 }
135}
136
137impl<T, D> Copy for Unchecked<T, D> where T: Copy {}
138
139impl<T, D> Unchecked<T, D> {
140 pub fn check(self) -> Option<Checked<T, D>> {
144 self.v.map(|v| Checked {
145 v,
146 _deref: PhantomData,
147 })
148 }
149}
150
151macro_rules! impl_op {
152 ($op:tt,$checked_op:tt,$method:ident,$checked_method:ident) => {
153 impl<T, D, Rhs> $op<Rhs> for Checked<T, D>
154 where
155 T: $checked_op<Rhs>,
156 {
157 type Output = Unchecked<<T as $checked_op<Rhs>>::Output, D>;
158
159 fn $method(self, rhs: Rhs) -> Self::Output {
160 Unchecked {
161 v: self.v.$checked_method(rhs),
162 _deref: self._deref,
163 }
164 }
165 }
166
167 impl<T, D, Rhs> $op<Rhs> for Unchecked<T, D>
168 where
169 T: $checked_op<Rhs>,
170 {
171 type Output = Unchecked<<T as $checked_op<Rhs>>::Output, D>;
172
173 fn $method(self, rhs: Rhs) -> Self::Output {
174 Unchecked {
175 v: self.v.and_then(|v| v.$checked_method(rhs)),
176 _deref: self._deref,
177 }
178 }
179 }
180 };
181}
182
183impl_op!(Add, CheckedAdd, add, checked_add);
184impl_op!(Sub, CheckedSub, sub, checked_sub);
185impl_op!(Mul, CheckedMul, mul, checked_mul);
186impl_op!(Div, CheckedDiv, div, checked_div);
187
188impl<T, D1, D2> PartialEq<Checked<T, D1>> for Checked<T, D2>
189where
190 T: PartialEq<T>,
191{
192 fn eq(&self, other: &Checked<T, D1>) -> bool {
193 self.v.eq(&other.v)
194 }
195}
196impl<T, D1> Eq for Checked<T, D1> where T: PartialEq<T> {}
197
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202
203 #[test]
204 fn it_works() {
205 assert_eq!(
206 *{ Checked::new_with_deref(1u8) * 12 - 2 }
207 .check()
208 .expect("no oveflow"),
209 10
210 );
211
212 assert_eq!(
213 { Checked::new(1u8) * 12 - 2 }.check().expect("no oveflow"),
214 Checked::new(10)
215 );
216
217 assert!({ Checked::new(1u8) + u8::MAX }.check().is_none());
218 assert!({ Checked::new(255u8) + 5 - 100 }.check().is_none());
219 }
220}