1#[macro_export]
2macro_rules! wrap {
61
62 (#[derive($($derive:ident),*)] $wid:ident<$tid:ident: $bound:path>: $new:item $($item:item)*) => {
64 #[derive($($derive),*)]
65
66 #[doc = concat!(
67 "See [`",
68 stringify!($wid),
69 "::new`].",
70 )]
71 pub struct $wid<$tid: $bound>($tid);
72
73 impl<$tid: $bound> $wid<$tid> {
74 $new
75 $($item)*
76
77 #[doc = concat!(
78 "Construct a `",
79 stringify!($wid),
80 "<T>` without checking that the inner value is valid. ",
81 "If it is not, it may result in undefined behaviour.",
82 )]
83 #[allow(dead_code)]
84 pub fn new_unchecked(inner: $tid) -> Self {
85 if cfg!(debug_assertions) {
86 Self::new(inner).unwrap()
87 } else {
88 Self(inner)
89 }
90 }
91
92 #[allow(dead_code)]
94 pub fn unwrap(self) -> $tid {
95 self.0
96 }
97
98 #[doc = concat!(
99 "Map a `",
100 stringify!($wid),
101 "<T>` to a `",
102 stringify!($wid),
103 "<U>` by applying a function to the wrapped value. ",
104 "It does not check that the value returned by the function is valid. ",
105 "If it is not, it may result in undefined behaviour.",
106 )]
107 #[allow(dead_code)]
108 pub fn map_unchecked<F, U>(self, f: F) -> $wid<U>
109 where
110 F: FnOnce(T) -> U,
111 U: $bound,
112 {
113 let inner = self.unwrap();
114 let new_inner: U = f(inner);
115 $wid(new_inner)
116 }
117 }
118
119 impl<T: $bound> std::ops::Deref for $wid<T> {
120 type Target = T;
121 fn deref(&self) -> &T {
122 &self.0
123 }
124 }
125
126 impl<T: $bound> std::convert::AsRef<T> for $wid<T> {
127 fn as_ref(&self) -> &T {
128 &self.0
129 }
130 }
131
132 impl<T: $bound> std::borrow::Borrow<T> for $wid<T> {
133 fn borrow(&self) -> &T {
134 &self.0
135 }
136 }
137
138 impl<T, U> std::cmp::PartialEq<$wid<T>> for $wid<U>
139 where
140 T: $bound,
141 U: $bound + std::cmp::PartialEq<T>,
142 {
143 fn eq(&self, rhs: &$wid<T>) -> bool {
144 self.0 == rhs.0
145 }
146 }
147
148 impl<T> std::cmp::Eq for $wid<T>
149 where
150 T: $bound + std::cmp::Eq,
151 {}
152
153 impl<T, U> std::cmp::PartialOrd<$wid<T>> for $wid<U>
154 where
155 T: $bound,
156 U: $bound + std::cmp::PartialOrd<T>,
157 {
158 fn partial_cmp(&self, rhs: &$wid<T>) -> std::option::Option<std::cmp::Ordering> {
159 std::cmp::PartialOrd::partial_cmp(&self.0, &rhs.0)
160 }
161 }
162
163 impl<T> std::cmp::Ord for $wid<T>
164 where
165 T: $bound + std::cmp::Eq + std::cmp::Ord,
166 {
167 fn cmp(&self, rhs: &$wid<T>) -> std::cmp::Ordering {
168 std::cmp::Ord::cmp(&self.0, &rhs.0)
169 }
170 }
171
172
173 impl<T> std::hash::Hash for $wid<T>
174 where
175 T: $bound + std::hash::Hash,
176 {
177 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
178 self.0.hash(state);
179 }
180 }
181 };
182
183 ($wid:ident<$tid:ident: $bound:path>: $new:item $($item:item)*) => {
185 $crate::wrap!( #[derive(Clone, Copy, Debug)] $wid<$tid: $bound>: $new $($item)* );
186
187 };
188
189 ($wid:ident borrowing str: $new:item $($item:item)*) => {
191 $crate::wrap!{
192 #[derive(Clone, Copy)]
193 $wid borrowing str:
194
195 $new
196
197 $($item)*
198
199 pub fn as_str(&self) -> &str {
201 self.0.borrow()
202 }
203 }
204
205 impl<T: std::borrow::Borrow<str>> std::fmt::Debug for $wid<T> {
206 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
207 write!(f, "{}({:?})", stringify!($wid), self.0.borrow())
208 }
209 }
210 };
211
212 (#[derive($($derive:ident),*)] $wid:ident borrowing $bid:ty: $new:item $($item:item)*) => {
215 $crate::wrap!( #[derive($($derive),*)] $wid<T: std::borrow::Borrow<$bid>>: $new $($item)* );
216
217 impl<T> $wid<T>
218 where
219 T: std::borrow::Borrow<$bid>,
220 {
221 #[doc = concat!(
222 "Convert from `&",
223 stringify!($wid),
224 "<T>` to `",
225 stringify!($wid),
226 "<&",
227 stringify!($bid),
228 ">`.",
229 )]
230 #[allow(dead_code)]
231 pub fn as_ref(&self) -> $wid<&$bid> {
232 $wid(self.0.borrow())
233 }
234 }
235
236 impl $wid<&'static $bid> {
237 #[doc = concat!(
238 "Construct a `",
239 stringify!($wid),
240 "<&'static ",
241 stringify!($bid),
242 ">` without checking that the inner value is valid. ",
243 "If it is not, it may result in undefined behaviour.",
244 )]
245 #[allow(dead_code)]
246 #[must_use] pub const fn new_unchecked_const(inner: &'static $bid) -> Self {
247 $wid(inner)
248 }
249 }
250
251 impl<T: std::borrow::Borrow<$bid>> std::convert::AsRef<$bid> for $wid<T> {
252 fn as_ref(&self) -> &$bid {
253 &self.0.borrow()
254 }
255 }
256
257 impl<T: std::borrow::Borrow<$bid>> std::borrow::Borrow<$bid> for $wid<T> {
258 fn borrow(&self) -> &$bid {
259 &self.0.borrow()
260 }
261 }
262
263 impl<T> std::cmp::PartialEq<$bid> for $wid<T>
264 where
265 T: std::borrow::Borrow<$bid>,
266 $bid: std::cmp::PartialEq,
267 {
268 fn eq(&self, other: &$bid) -> bool {
269 self.0.borrow() == other
270 }
271 }
272
273 impl<T> std::cmp::PartialEq<$wid<T>> for $bid
274 where
275 T: std::borrow::Borrow<$bid>,
276 $bid: std::cmp::PartialEq,
277 {
278 fn eq(&self, other: &$wid<T>) -> bool {
279 self == other.0.borrow()
280 }
281 }
282
283 impl<T> std::cmp::PartialOrd<$bid> for $wid<T>
284 where
285 T: std::borrow::Borrow<$bid>,
286 $bid: std::cmp::PartialOrd,
287 {
288 fn partial_cmp(&self, other: &$bid) -> std::option::Option<std::cmp::Ordering> {
289 self.0.borrow().partial_cmp(other)
290 }
291 }
292
293 impl<T> std::cmp::PartialOrd<$wid<T>> for $bid
294 where
295 T: std::borrow::Borrow<$bid>,
296 $bid: std::cmp::PartialOrd,
297 {
298 fn partial_cmp(&self, other: &$wid<T>) -> std::option::Option<std::cmp::Ordering> {
299 self.partial_cmp(other.0.borrow())
300 }
301 }
302 };
303
304 ($wid:ident borrowing $bid:ty: $new:item $($item:item)*) => {
306 $crate::wrap!( #[derive(Clone, Copy, Debug)] $wid borrowing $bid: $new $($item)* );
307 };
308}
309
310#[cfg(test)]
311pub mod test_simple_wrap {
312 pub trait Number {
313 fn even(&self) -> bool;
314 }
315 impl Number for i32 {
316 fn even(&self) -> bool {
317 *self % 2 == 0
318 }
319 }
320 impl Number for isize {
321 fn even(&self) -> bool {
322 *self % 2 == 0
323 }
324 }
325
326 wrap! { Even<T: Number>:
327 pub fn new(inner: T) -> Result<Self, ()> {
328 if inner.even() {
329 Ok(Even(inner))
330 } else {
331 Err(())
332 }
333 }
334 }
335
336 #[test]
337 fn constructor_succeeds() {
338 assert!(Even::new(42).is_ok());
339 }
340
341 #[test]
342 fn constructor_fails() {
343 assert!(Even::new(43).is_err());
344 }
345
346 #[allow(dead_code)]
348 fn unwrap() {
349 let even = Even(42);
350 let _: isize = even.unwrap();
351 }
352
353 #[allow(dead_code)]
355 fn deref() {
356 let even = Even(42);
357 let _: &isize = &even;
358 }
359
360 #[allow(dead_code)]
362 fn as_ref() {
363 let even = Even(42);
364 let _: &isize = even.as_ref();
365 }
366
367 #[allow(dead_code)]
369 fn borrow() {
370 use std::borrow::Borrow;
371 let even = Even(42);
372 let _: &isize = even.borrow();
373 }
374}
375
376#[cfg(test)]
377pub mod test_wrap_borrowing {
378 wrap! { Foo borrowing str :
379 pub fn new(inner: T) -> Result<Self, ()> {
381 if inner.borrow().contains("foo") {
382 Ok(Foo(inner))
383 } else {
384 Err(())
385 }
386 }
387 }
388
389 #[test]
390 fn new_succeeds() {
391 assert!(Foo::new("this foo is good").is_ok());
392 }
393
394 #[test]
395 fn new_fails() {
396 assert!(Foo::new("this bar is bad").is_err());
397 }
398
399 #[test]
400 fn partial_eq() {
401 let f1a = Foo::new("foo1".to_string()).unwrap();
402 let f1b = Foo::new("foo1").unwrap();
403 let f2 = Foo::new("foo2").unwrap();
404 assert_eq!(&f1a, "foo1");
405 assert_eq!(&f1a, "foo1");
406 assert_eq!(&f2, "foo2");
407 assert_ne!(&f2, "foo1");
408 assert_eq!("foo1", &f1a);
409 assert_eq!("foo1", &f1a);
410 assert_eq!("foo2", &f2);
411 assert_ne!("foo1", &f2);
412 assert_eq!(f1a.as_str(), f1b.as_str());
413 }
414
415 #[allow(dead_code)]
417 fn new_unchecked() {
418 let _: Foo<String> = Foo::new_unchecked(String::new());
419 }
420
421 #[allow(dead_code)]
423 fn unwrap() {
424 let foo = Foo("foo".to_string());
425 let _: String = foo.unwrap();
426 }
427
428 #[allow(dead_code)]
430 fn deref() {
431 let foo = Foo("this foo is good".to_string());
432 let _: &String = &foo;
433 let _: &str = &foo;
434 }
435
436 #[allow(dead_code)]
438 fn as_ref_trait() {
439 let foo = Foo("this foo is good".to_string());
440 let _: &String = AsRef::as_ref(&foo);
441 let _: &str = AsRef::as_ref(&foo);
442 }
443
444 #[allow(dead_code)]
446 fn borrow() {
447 use std::borrow::Borrow;
448 let foo = Foo("this foo is good".to_string());
449 let _: &String = foo.borrow();
450 let _: &str = foo.borrow();
451 }
452
453 #[allow(dead_code)]
455 fn as_ref() {
456 let foo = Foo("this foo is good".to_string());
457 let _: Foo<&str> = foo.as_ref();
458 }
459}