push-trait 0.6.0

Push trait for collectons.
Documentation
use super::{Nothing, PushedVal};


// TODO: this is a hack
trait IntoPo {
    type Po;
    fn into_po(self) -> Option<Self::Po>;
}
impl<T> IntoPo for Option<T> {
    type Po = T;

    #[inline]
    fn into_po(self) -> Option<T> {
        self
    }
}
impl IntoPo for bool {
    type Po = PushedVal;

    #[inline]
    fn into_po(self) -> Option<PushedVal> {
        if self { None } else { Some(PushedVal) }
    }
}
impl IntoPo for () {
    type Po = Nothing;

    #[inline]
    fn into_po(self) -> Option<Self::Po> {
        None
    }
}


#[cfg(feature = "alloc")]
macro_rules! do_impl {
    (CanPush for $impl_for:ty, $t:ty, $po:ty; $($gen:tt)*) => {
        impl<$($gen)*> $crate::base::CanPush<$t> for $impl_for {
            type PushedOut = $po;
        }
    };
    (Push for $impl_for:ty, $method:path, $t:ty, $po:ty; $($gen:tt)*) => {
        do_impl!(CanPush for $impl_for, $t, $po; $($gen)*);
        impl<$($gen)*> $crate::base::Push<$t> for $impl_for {
            fn push(&mut self, val: $t) -> Option<Self::PushedOut> {
                $crate::impls::IntoPo::into_po($method(self, val))
            }
        }
    };
    (keyval Push for $impl_for:ty, $method:path, $t:ty, $po:ty; $($gen:tt)*) => {
        do_impl!(CanPush for $impl_for, $t, $po; $($gen)*);
        impl<$($gen)*> $crate::base::Push<$t> for $impl_for {
            fn push(&mut self, (key, val): $t) -> Option<Self::PushedOut> {
                $crate::impls::IntoPo::into_po($method(self, key, val))
            }
        }
    };
    (PushSorted for $impl_for:ty, $method:path, $t:ty, $po:ty; $($gen:tt)*) => {
        do_impl!(CanPush for $impl_for, $t, $po; $($gen)*);
        impl<$($gen)*> $crate::sorted::PushSorted<$t> for $impl_for {
            fn push_sorted(&mut self, val: $t) -> Option<Self::PushedOut> {
                $crate::impls::IntoPo::into_po($method(self, val))
            }
        }
    };
    (keyval PushSorted for $impl_for:ty, $method:path, $t:ty, $po:ty; $($gen:tt)*) => {
        do_impl!(CanPush for $impl_for, $t, $po; $($gen)*);
        impl<$($gen)*> $crate::sorted::PushSorted<$t> for $impl_for {
            fn push_sorted(&mut self, (key, val): $t) -> Option<Self::PushedOut> {
                $crate::impls::IntoPo::into_po($method(self, key, val))
            }
        }
    };
    (PushBack for $impl_for:ty, $method:path, $t:ty, $po:ty; $($gen:tt)*) => {
        do_impl!(Push for $impl_for, $method, $t, $po; $($gen)*);
        impl<$($gen)*> $crate::ordered::PushBack<$t> for $impl_for { }
    };
    (keyval PushBack for $impl_for:ty, $method:path, $t:ty, $po:ty; $($gen:tt)*) => {
        do_impl!(keyval Push for $impl_for, $method, $t, $po; $($gen)*);
        impl<$($gen)*> $crate::ordered::PushBack<$t> for $impl_for { }
    };
    (PushFront for $impl_for:ty, $method:path, $t:ty, $po:ty; $($gen:tt)*) => {
        impl<$($gen)*> $crate::ordered::PushFront<$t> for $impl_for {
            fn push_front(&mut self, val: $t) -> Option<Self::PushedOut> {
                $crate::impls::IntoPo::into_po($method(self, val))
            }
        }
    };
    (Insert for $impl_for:ty, $method:path, $t:ty, $po:ty; $($gen:tt)*) => {
        impl<$($gen)*> $crate::ordered::Insert<$t> for $impl_for {
            fn insert(&mut self, index: usize, val: $t) -> Option<Self::PushedOut> {
                $crate::impls::IntoPo::into_po($method(self, index, val))
            }
        }
    };
    (Append for $impl_for:ty, $method:path; $($gen:tt)*) => {
        impl<$($gen)*> $crate::append::Append for $impl_for {
            fn append(&mut self, val: &mut Self) {
                $method(self, val)
            }
        }
    };
    (AppendBack for $impl_for:ty, $method:path; $($gen:tt)*) => {
        do_impl!(Append for $impl_for, $method; $($gen)*);
        impl<$($gen)*> $crate::append::AppendBack for $impl_for {}
        impl<$($gen)*> $crate::append::AppendFront for $impl_for {}
    };
}

#[cfg_attr(feature = "cargo-clippy", allow(linkedlist))]
// TODO: https://github.com/Manishearth/rust-clippy/issues/1800
cfg_if! {
    if #[cfg(feature = "alloc")] {
        cfg_if! {
            if #[cfg(feature = "std")] {
                use std::collections;
            } else {
                use alloc::{self as collections, String, Vec};
            }
        }
        use self::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};

        do_impl!(Append for BTreeSet<T>, BTreeSet::append; T: Ord);
        do_impl!(PushSorted for BTreeSet<T>, BTreeSet::insert, T, super::PushedVal; T: Ord);

        do_impl!(Append for BinaryHeap<T>, BinaryHeap::append; T: Ord);
        do_impl!(PushSorted for BinaryHeap<T>, BinaryHeap::push, T, super::Nothing; T: Ord);

        do_impl!(Append for BTreeMap<K, V>, BTreeMap::append; K: Ord, V);
        do_impl!(keyval PushSorted for BTreeMap<K, V>, BTreeMap::insert, (K, V), V; K: Ord, V);

        do_impl!(AppendBack for LinkedList<T>, LinkedList::append; T);
        do_impl!(PushBack for LinkedList<T>, LinkedList::push_back, T, super::Nothing; T);
        do_impl!(PushFront for LinkedList<T>, LinkedList::push_front, T, super::Nothing; T);

        do_impl!(AppendBack for String, string_append; );
        do_impl!(PushBack for String, String::push, char, super::Nothing; );
        do_impl!(PushBack for String, String::push_str, &'a str, super::Nothing; 'a);
        do_impl!(Insert for String, String::insert, char, super::Nothing; );
        do_impl!(Insert for String, String::insert_str, &'a str, super::Nothing; 'a);
        fn string_append(lhs: &mut String, rhs: &mut String) {
            lhs.push_str(rhs);
            rhs.clear();
        }

        do_impl!(AppendBack for Vec<T>, Vec::append; T);
        do_impl!(PushBack for Vec<T>, Vec::push, T, super::Nothing; T);
        do_impl!(PushBack for Vec<u8>, push_utf8_char, char, super::Nothing; );
        do_impl!(PushBack for Vec<u16>, push_utf16_char, char, super::Nothing; );
        do_impl!(PushBack for Vec<u32>, push_utf32_char, char, super::Nothing; );
        do_impl!(PushBack for Vec<T>,
                 Vec::extend_from_slice, &'a [T], super::Nothing; 'a, T: 'a + Clone);
        do_impl!(Insert for Vec<T>, Vec::insert, T, super::Nothing; T);
        do_impl!(Insert for Vec<u32>, insert_utf32_char, char, super::Nothing; );
        fn push_utf8_char(lhs: &mut Vec<u8>, rhs: char) {
            let mut buf = [0; 4];
            Vec::extend_from_slice(lhs, rhs.encode_utf8(&mut buf).as_bytes())
        }
        fn push_utf16_char(lhs: &mut Vec<u16>, rhs: char) {
            let mut buf = [0; 2];
            Vec::extend_from_slice(lhs, rhs.encode_utf16(&mut buf))
        }
        fn push_utf32_char(lhs: &mut Vec<u32>, rhs: char) {
            Vec::push(lhs, rhs as u32)
        }
        fn insert_utf32_char(lhs: &mut Vec<u32>, index: usize, rhs: char) {
            Vec::insert(lhs, index, rhs as u32)
        }

        cfg_if! {
            if #[cfg(feature = "nightly")] {
                do_impl!(Insert for Vec<u8>, insert_utf8_char, char, super::Nothing; );
                do_impl!(Insert for Vec<u16>, insert_utf16_char, char, super::Nothing; );
                do_impl!(Insert for Vec<T>,
                         insert_slice, &'a [T], super::Nothing; 'a, T: 'a + Clone);
                fn insert_utf8_char(lhs: &mut Vec<u8>, index: usize, rhs: char) {
                    let mut buf = [0; 4];
                    Vec::splice(lhs, index..index, rhs.encode_utf8(&mut buf).bytes());
                }
                fn insert_utf16_char(lhs: &mut Vec<u16>, index: usize, rhs: char) {
                    let mut buf = [0; 2];
                    Vec::splice(lhs, index..index, rhs.encode_utf16(&mut buf).iter().cloned());
                }
                fn insert_slice<T: Clone>(lhs: &mut Vec<T>, index: usize, rhs: &[T]) {
                    Vec::splice(lhs, index..index, rhs.iter().cloned());
                }
            }
        }

        do_impl!(AppendBack for VecDeque<T>, VecDeque::append; T);
        do_impl!(PushBack for VecDeque<T>, VecDeque::push_back, T, super::Nothing; T);
        do_impl!(PushFront for VecDeque<T>, VecDeque::push_front, T, super::Nothing; T);
        do_impl!(Insert for VecDeque<T>, VecDeque::insert, T, super::Nothing; T);
    }
}

cfg_if! {
    if #[cfg(feature = "std")] {
        use std::collections::{HashMap, HashSet};
        use std::ffi::{OsStr, OsString};
        use std::hash::Hash;

        do_impl!(AppendBack for OsString, os_string_append; );
        do_impl!(PushBack for OsString, OsString::push, &'a OsStr, super::Nothing; 'a);
        do_impl!(PushBack for OsString, OsString::push, &'a str, super::Nothing; 'a);
        fn os_string_append(lhs: &mut OsString, rhs: &mut OsString) {
            lhs.push(&rhs);
            rhs.clear();
        }

        do_impl!(keyval Push for HashMap<K, V>, HashMap::insert, (K, V), V; K: Hash + Eq, V);
        do_impl!(Push for HashSet<T>, HashSet::insert, T, super::PushedVal; T: Hash + Eq);
    }
}