weak_true/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![doc = include_str!("../README.md")]
3
4#[cfg(feature = "std")]
5use ::std;
6#[cfg(not(feature = "std"))]
7extern crate alloc as std;
8
9use core::{
10    borrow::{
11        Borrow,
12        BorrowMut,
13    },
14    convert::{
15        identity,
16        Infallible
17    },
18    ffi::CStr,
19    fmt::Debug,
20    hash::{
21        Hash,
22        Hasher,
23    },
24    iter::FusedIterator,
25    ops::Deref,
26    pin::Pin,
27    task::Poll,
28};
29use std::{
30    borrow::{
31        Cow,
32        ToOwned,
33    },
34    boxed::Box,
35    collections::{
36        BTreeMap,
37        BTreeSet,
38        BinaryHeap,
39        LinkedList,
40        VecDeque,
41    },
42    ffi::CString,
43    rc::Rc,
44    string::String,
45    sync::Arc,
46    vec::Vec,
47};
48#[cfg(feature = "std")]
49use std::{
50    collections::{
51        HashMap,
52        HashSet,
53    },
54    ffi::{
55        OsStr,
56        OsString,
57    }
58};
59
60/// Add [`WeakTrue::weak_true`] call in `if`, `while`
61///
62/// # Examples
63/// ```
64/// use weak_true::weak_true;
65///
66/// #[weak_true]
67/// fn main() {
68///     let mut a = vec![1, 2, 3];
69///     let mut b = vec![5, 4];
70///
71///     while a {
72///         b.push(a.pop().unwrap());
73///     }
74///
75///     assert_eq!(b, vec![5, 4, 3, 2, 1]);
76/// }
77/// ```
78///
79/// ```
80/// # use weak_true::weak_true;
81/// #[weak_true]
82/// fn main() {
83///     let mut a = vec![-1, 0, 1, 2];
84///     let mut b = vec![4, 3];
85///
86///     while a && a[a.len()-1] {
87///         b.push(a.pop().unwrap());
88///     }
89///
90///     assert_eq!(a, vec![-1, 0]);
91///     assert_eq!(b, vec![4, 3, 2, 1]);
92/// }
93/// ```
94#[cfg(feature = "macros")]
95pub use weak_true_proc_macro::weak_true;
96
97/// Similar to the automatic implicit conversion to boolean values
98/// in weakly typed languages
99///
100/// | type                          | impl                  |
101/// | ---                           | ---                   |
102/// | float                         | self is not 0.0 / NaN |
103/// | integer                       | self != 0             |
104/// | reference / smart pointer     | inner value impl      |
105/// | raw pointer                   | !self.is_null         |
106/// | Option                        | self.is_some          |
107/// | Result                        | self.is_ok            |
108/// | Poll                          | self.is_ready         |
109/// | str / slice / array           | !self.is_empty        |
110/// | collections                   | !self.is_empty        |
111/// | unit                          | false                 |
112/// | bool                          | self                  |
113/// | fn / tuple / char             | true                  |
114pub trait WeakTrue {
115    /// Similar to the automatic implicit conversion to boolean values
116    /// in weakly typed languages
117    ///
118    /// # Examples
119    /// ```
120    /// # use weak_true::WeakTrue;
121    ///
122    /// assert!("c".weak_true());
123    /// assert!('c'.weak_true());
124    /// assert!('\0'.weak_true());
125    /// assert!([0].weak_true());
126    /// assert!((&0 as *const i32).weak_true());
127    /// assert!(Some(0).weak_true());
128    ///
129    /// assert!(f64::NAN.weak_false());
130    /// assert!(0.0.weak_false());
131    /// assert!(0.weak_false());
132    /// assert!("".weak_false());
133    /// assert!([0; 0].weak_false());
134    /// ```
135    ///
136    /// Refer to the documentation on [`WeakTrue`]
137    ///
138    /// [`WeakTrue`]: crate::WeakTrue
139    fn weak_true(&self) -> bool;
140
141    /// Default implementation is [`weak_true`] inversion
142    ///
143    /// [`weak_true`]: crate::WeakTrue::weak_true
144    fn weak_false(&self) -> bool {
145        !self.weak_true()
146    }
147
148    /// Run [`bool::then`] on [`WeakTrue::weak_true`]
149    ///
150    /// # Examples
151    /// ```
152    /// # use weak_true::WeakTrue;
153    ///
154    /// assert_eq!(1.weak_then(|| "a"), Some("a"));
155    /// assert_eq!(0.weak_then(|| "a"), None);
156    /// ```
157    fn weak_then<F, R>(&self, f: F) -> Option<R>
158    where F: FnOnce() -> R,
159          Self: Sized,
160    {
161        self.weak_true().then(f)
162    }
163
164    /// Run [`bool::then`] on [`WeakTrue::weak_false`]
165    ///
166    /// # Examples
167    /// ```
168    /// # use weak_true::WeakTrue;
169    ///
170    /// assert_eq!(1.weak_else(|| "a"), None);
171    /// assert_eq!(0.weak_else(|| "a"), Some("a"));
172    /// ```
173    fn weak_else<F, R>(&self, f: F) -> Option<R>
174    where F: FnOnce() -> R,
175          Self: Sized,
176    {
177        self.weak_false().then(f)
178    }
179}
180
181fn weak_bool<const B: bool>(value: impl WeakTrue) -> bool {
182    if B {
183        value.weak_true()
184    } else {
185        value.weak_false()
186    }
187}
188pub trait WeakBoolIterExtend: Sized {
189    /// like `iter.map(WeakTrue::weak_true)`
190    fn weak_true(self) -> WeakBoolIter<true, Self>;
191
192    /// like `iter.map(WeakTrue::weak_false)`
193    fn weak_false(self) -> WeakBoolIter<false, Self>;
194
195    /// like `iter.weak_true().all(identity)`
196    fn weak_all(self) -> bool;
197
198    /// like `iter.weak_true().any(identity)`
199    fn weak_any(self) -> bool;
200}
201impl<I> WeakBoolIterExtend for I
202where I: Iterator,
203      I::Item: WeakTrue,
204{
205    fn weak_true(self) -> WeakBoolIter<true, Self> {
206        WeakBoolIter(self)
207    }
208
209    fn weak_false(self) -> WeakBoolIter<false, Self> {
210        WeakBoolIter(self)
211    }
212
213    fn weak_all(self) -> bool {
214        self.weak_true().all(identity)
215    }
216
217    fn weak_any(self) -> bool {
218        self.weak_true().any(identity)
219    }
220}
221
222/// Created from [`weak_true`] and [`weak_false`] method
223///
224/// [`weak_true`]: crate::WeakBoolIterExtend::weak_true
225/// [`weak_false`]: crate::WeakBoolIterExtend::weak_false
226#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
227pub struct WeakBoolIter<const B: bool, I: ?Sized>(I);
228
229impl<const B: bool, I> WeakBoolIter<B, I> {
230    /// Consumes [`WeakBoolIter`] into wrapped `I`
231    ///
232    /// [`WeakBoolIter`]: crate::WeakBoolIter
233    ///
234    /// # Examples
235    /// ```
236    /// # use weak_true::{WeakTrue, WeakBoolIter, WeakBoolIterExtend};
237    /// # use std::slice;
238    /// type I<'a> = slice::Iter<'a, i32>;
239    ///
240    /// let i: I<'_> = [0, 2][..].iter();
241    /// let wrapped: WeakBoolIter<true, I<'_>> = i.weak_true();
242    /// let _i: I<'_> = wrapped.into_inner();
243    /// ```
244    pub fn into_inner(self) -> I {
245        self.0
246    }
247}
248impl<const B: bool, I> From<I> for WeakBoolIter<B, I> {
249    fn from(value: I) -> Self {
250        Self(value)
251    }
252}
253impl<const B: bool, I: Hash + ?Sized> Hash for WeakBoolIter<B, I> {
254    fn hash<H: Hasher>(&self, state: &mut H) {
255        self.0.hash(state);
256    }
257}
258impl<const B: bool, I: ?Sized> Borrow<I> for WeakBoolIter<B, I> {
259    fn borrow(&self) -> &I {
260        &self.0
261    }
262}
263impl<const B: bool, I: ?Sized> BorrowMut<I> for WeakBoolIter<B, I> {
264    fn borrow_mut(&mut self) -> &mut I {
265        &mut self.0
266    }
267}
268impl<const B: bool, I, U> AsRef<U> for WeakBoolIter<B, I>
269where I: AsRef<U> + ?Sized,
270{
271    fn as_ref(&self) -> &U {
272        self.0.as_ref()
273    }
274}
275impl<const B: bool, I, U> AsMut<U> for WeakBoolIter<B, I>
276where I: AsMut<U> + ?Sized,
277{
278    fn as_mut(&mut self) -> &mut U {
279        self.0.as_mut()
280    }
281}
282impl<const B: bool, I> Debug for WeakBoolIter<B, I>
283where I: Debug + ?Sized,
284{
285    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
286        f
287            .debug_tuple(if B {
288                "WeakBoolIter<true>"
289            } else {
290                "WeakBoolIter<false>"
291            })
292            .field(&&self.0)
293            .finish()
294    }
295}
296impl<const B: bool, I> ExactSizeIterator for WeakBoolIter<B, I>
297where I::Item: WeakTrue,
298      I: ExactSizeIterator + ?Sized,
299{
300}
301impl<const B: bool, I> FusedIterator for WeakBoolIter<B, I>
302where I::Item: WeakTrue,
303      I: FusedIterator + ?Sized,
304{
305}
306impl<const B: bool, I> Iterator for WeakBoolIter<B, I>
307where I: Iterator + ?Sized,
308      I::Item: WeakTrue,
309{
310    type Item = bool;
311
312    fn next(&mut self) -> Option<Self::Item> {
313        self.0.next().map(weak_bool::<B>)
314    }
315
316    fn nth(&mut self, n: usize) -> Option<Self::Item> {
317        self.0.nth(n).map(weak_bool::<B>)
318    }
319
320    fn fold<B1, F>(mut self, init: B1, mut f: F) -> B1
321    where Self: Sized,
322          F: FnMut(B1, Self::Item) -> B1,
323    {
324        (&mut self.0)
325            .fold(init, |acc, elem|
326                f(acc, weak_bool::<B>(elem)))
327    }
328
329    fn size_hint(&self) -> (usize, Option<usize>) {
330        self.0.size_hint()
331    }
332}
333impl<const B: bool, I> DoubleEndedIterator for WeakBoolIter<B, I>
334where I: DoubleEndedIterator + ?Sized,
335      I::Item: WeakTrue,
336{
337    fn next_back(&mut self) -> Option<Self::Item> {
338        self.0.next_back().map(weak_bool::<B>)
339    }
340
341    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
342        self.0.nth_back(n).map(weak_bool::<B>)
343    }
344
345    fn rfold<B1, F>(mut self, init: B1, mut f: F) -> B1
346    where Self: Sized,
347          F: FnMut(B1, Self::Item) -> B1,
348    {
349        (&mut self.0)
350            .rfold(init, |acc, elem|
351                f(acc, weak_bool::<B>(elem)))
352    }
353}
354
355#[doc = "\
356if but use [`weak_true`] result value
357
358# Examples
359```
360# use weak_true::wif;
361let r = wif!(\"\" => {
362    1
363} else {
364    0
365});
366assert_eq!(r, 0);
367
368wif!(\"\" => {
369    unreachable!()
370});
371wif!('\\0' => { } else {
372    unreachable!()
373});
374```
375
376[`weak_true`]: crate::WeakTrue::weak_true
377"]
378#[macro_export]
379macro_rules! wif {
380    ($cond:expr => $true:block $(else $false:block)?) => {
381        if $crate::WeakTrue::weak_true(&$cond)
382        $true $(else $false)?
383    };
384}
385
386macro_rules! impls {
387    ($self:ident {
388        $(
389            $cond:expr =>
390            $(
391                $(#[$meta:meta])*
392                $ty:ty $(=> [$($g:tt)*] $(($($w:tt)*))?)?
393            ),+ $(,)?;
394        )*
395    }) => {
396        $(
397            impls!(@impl($self) $cond => $(
398                    $(#[$meta])*
399                    $ty $(=> [$($g)*] $(($($w)*))?)?
400            ),+);
401        )*
402    };
403    (
404        @impl($self:ident)
405        $cond:expr =>
406        $(
407            $(#[$meta:meta])*
408            $ty:ty $(=> [$($g:tt)*] $(($($w:tt)*))?)?
409        ),+
410    ) => {
411        $(
412            $(#[$meta])*
413            impl$(<$($g)*>)? WeakTrue for $ty $($(where $($w)*)?)? {
414                fn weak_true(&$self) -> bool {
415                    $cond
416                }
417            }
418        )+
419    };
420}
421
422impls!(self {
423    unreachable!()  => Infallible;
424    false           => ();
425    *self           => bool;
426    true            => char, fn() -> R => [R];
427    *self != 0      => u8, u16, u32, u64, u128, usize,
428                       i8, i16, i32, i64, i128, isize;
429    *self != 0.0 && !self.is_nan() => f32, f64;
430    !self.is_empty() =>
431        str,
432        CStr,
433        #[cfg(feature = "std")]
434        OsStr,
435        String,
436        CString,
437        #[cfg(feature = "std")]
438        OsString,
439        [T]                 => [T],
440        [T; N]              => [T, const N: usize],
441        Vec<T>              => [T],
442        VecDeque<T>         => [T],
443        LinkedList<T>       => [T],
444        #[cfg(feature = "std")]
445        HashMap<K, V, H>    => [K, V, H],
446        #[cfg(feature = "std")]
447        HashSet<T, H>       => [T, H],
448        BTreeMap<K, V>      => [K, V],
449        BTreeSet<T>         => [T],
450        BinaryHeap<K>       => [K],
451        ;
452    (**self).weak_true() =>
453        &'_ T       => [T: WeakTrue + ?Sized],
454        &'_ mut T   => [T: WeakTrue + ?Sized],
455        Box<T>      => [T: WeakTrue + ?Sized],
456        Rc<T>       => [T: WeakTrue + ?Sized],
457        Arc<T>      => [T: WeakTrue + ?Sized],
458        Cow<'_, T>  => [T: WeakTrue + ?Sized + ToOwned],
459        Pin<T>      => [T: Deref](T::Target: WeakTrue),
460        ;
461    !self.is_null() =>
462        *const T    => [T: ?Sized],
463        *mut T      => [T: ?Sized],
464        ;
465    self.is_some()  => Option<T>    => [T];
466    self.is_ok()    => Result<T, E> => [T, E];
467    self.is_ready() => Poll<T>      => [T];
468});
469
470macro_rules! impl_tuples {
471    ($f:ident $($g:ident)*) => {
472        impl_tuples!($($g)*);
473        #[doc(hidden)]
474        impl<$f, $($g),*> WeakTrue for ($f, $($g),*) {
475            fn weak_true(&self) -> bool {
476                true
477            }
478        }
479        #[doc(hidden)]
480        impl<$f, R, $($g),*> WeakTrue for fn($f, $($g),*) -> R {
481            fn weak_true(&self) -> bool {
482                true
483            }
484        }
485    };
486    () => ();
487}
488
489impl_tuples!(T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16);
490
491#[cfg(test)]
492mod tests {
493    use core::fmt::Debug;
494    use core::ptr::{null, null_mut};
495    use crate::WeakBoolIterExtend;
496
497    use super::*;
498    use super::std::vec;
499
500    trait TestTrait: WeakTrue + Debug { }
501    impl<T: WeakTrue + Debug> TestTrait for T { }
502
503    macro_rules! run_data {
504        ($($e:expr),+ $(,)?) => {{
505            [$({
506                let __value: Box<dyn TestTrait>
507                    = Box::new($e);
508                __value
509            }),+]
510        }};
511    }
512
513    #[test]
514    fn test() {
515        let datas = run_data![
516            true,
517            1i32,
518            10u8,
519            &2,
520            "a",
521            &"a",
522            "ab",
523            '\0',
524            'c',
525            ['c'],
526            &['c'],
527            &['c'][..],
528            [0],
529            vec![0],
530            true,
531            (0,),
532            (0, 0),
533            (|| ()) as fn(),
534            (|| 0) as fn() -> i32,
535            (|_| ()) as fn(i32),
536            (|_| 0) as fn(i32) -> i32,
537            &0 as *const i32,
538            Some(0),
539            Ok::<_, ()>(0),
540            Some(1),
541            Ok::<_, ()>(1),
542        ];
543        assert!(datas.iter().weak_all());
544        for data in datas.iter().weak_true() {
545            assert!(data.weak_true(),   "{data:?}");
546            assert!(!data.weak_false(), "{data:?}");
547        }
548        for data in datas.iter().weak_false() {
549            assert!(! data.weak_true(),   "{data:?}");
550            assert!(! !data.weak_false(), "{data:?}");
551        }
552        for data in datas {
553            assert!(data.weak_true(),   "{data:?}");
554            assert!(!data.weak_false(), "{data:?}");
555        }
556    }
557
558    #[test]
559    fn test_false() {
560        let datas = run_data![
561            false,
562            0,
563            0.0,
564            0.0f32,
565            f32::NAN,
566            f64::NAN,
567            &0,
568            &0.0,
569            &0.0f32,
570            &f32::NAN,
571            &f64::NAN,
572            [0; 0],
573            &[0; 0][..],
574            null::<i32>(),
575            null_mut::<i32>(),
576            vec![0; 0],
577            Vec::<i32>::new(),
578            BTreeSet::<i32>::new(),
579            None::<i32>,
580            Err::<(), _>(0),
581            Err::<(), _>(1),
582            "",
583            (),
584        ];
585        assert!(!datas.iter().weak_any());
586        for data in datas.iter().weak_true() {
587            assert!(data.weak_false(),  "{data:?}");
588            assert!(!data.weak_true(),  "{data:?}");
589        }
590        for data in datas.iter().weak_false() {
591            assert!(! data.weak_false(),  "{data:?}");
592            assert!(! !data.weak_true(),  "{data:?}");
593        }
594        for data in datas {
595            assert!(data.weak_false(),  "{data:?}");
596            assert!(!data.weak_true(),  "{data:?}");
597        }
598    }
599}