std_move/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4extern crate alloc;
5
6#[cfg(test)]
7use alloc::vec;
8use alloc::{
9    borrow::{Cow, ToOwned},
10    collections::*,
11    ffi::CString,
12    rc::Rc,
13    string::String,
14    sync::Arc,
15    vec::Vec,
16};
17use core::{
18    cmp,
19    marker::{PhantomData, PhantomPinned},
20    mem::MaybeUninit,
21    num::*,
22    ptr::NonNull,
23    task::Poll,
24};
25#[cfg(feature = "std")]
26use std::{collections::*, ffi::OsString, path::PathBuf};
27
28/// Simply copy self, or replace self with a simple instance
29pub trait StdMove: Sized {
30    /// Simply copy self, or replace self with a simple instance
31    #[must_use]
32    fn std_move(&mut self) -> Self;
33}
34
35/// [`Clone`] like impl macro
36#[macro_export]
37macro_rules! impl_trivial {
38    (@gen($self:ident)) => { $self.clone() };
39    (@gen($self:ident) {$($b:tt)*}) => {{ $($b)* }};
40    ($(
41        $(#[$meta:meta])*
42        $ty:ty $([$($g:tt)*])? $({$($b:tt)*})?
43    ),+ $(,)?) => {
44        $(
45            $(#[$meta])*
46            impl$(<$($g)*>)? $crate::StdMove for $ty {
47                fn std_move(&mut self) -> Self {
48                    $crate::impl_trivial!(@gen(self) $({$($b)*})?)
49                }
50            }
51        )+
52    };
53}
54/// [`take`] like impl macro
55///
56/// [`take`]: core::mem::take
57#[macro_export]
58macro_rules! impl_take {
59    (@gen($self:ident)) => { ::core::mem::take($self) };
60    (@gen($self:ident) {$($b:tt)*}) => {{ $($b)* }};
61    ($(
62        $(#[$meta:meta])*
63        $ty:ty $([$($g:tt)*])? $({$($b:tt)*})?
64    ),+ $(,)?) => {
65        $(
66            $(#[$meta])*
67            impl$(<$($g)*>)? $crate::StdMove for $ty {
68                fn std_move(&mut self) -> Self {
69                    $crate::impl_take!(@gen(self) $({$($b)*})?)
70                }
71            }
72        )+
73    };
74}
75macro_rules! impl_tuples {
76    () => {
77        impl_tuples! { () T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 }
78    };
79    (() $cur:ident $($rest:ident)*) => {
80        impl_tuples! {
81            @impl
82            /// This trait is implemented for tuples up to 12 items long.
83            $cur
84        }
85        impl_tuples! { ($cur) $($rest)* }
86    };
87    (($($c:ident)*)) => {};
88    (($($c:ident)*) $cur:ident $($rest:ident)*) => {
89        impl_tuples! {
90            @impl
91            #[doc(hidden)]
92            $($c)* $cur
93        }
94        impl_tuples! { ($($c)* $cur) $($rest)* }
95    };
96    (@impl $(#[$meta:meta])* $($i:ident)+) => {
97        $(#[$meta])*
98        impl<$($i),+> StdMove for ($($i,)+)
99        where $($i: StdMove,)+
100        {
101            fn std_move(&mut self) -> Self {
102                #[allow(non_snake_case)]
103                let ($($i,)+) = self;
104                ($($i.std_move(),)+)
105            }
106        }
107    };
108}
109
110impl<T: StdMove, const N: usize> StdMove for [T; N] {
111    fn std_move(&mut self) -> Self {
112        self.each_mut().map(StdMove::std_move)
113    }
114}
115impl<T: StdMove> StdMove for cmp::Reverse<T> {
116    fn std_move(&mut self) -> Self {
117        Self(self.0.std_move())
118    }
119}
120impl<T: ToOwned> StdMove for Cow<'_, T> where T::Owned: StdMove {
121    fn std_move(&mut self) -> Self {
122        match self {
123            Cow::Borrowed(x) => Self::Borrowed(*x),
124            Cow::Owned(x) => Self::Owned(x.std_move()),
125        }
126    }
127}
128impl<T> StdMove for MaybeUninit<T> {
129    fn std_move(&mut self) -> Self {
130        unsafe {
131            // SAFETY: MaybeUninit 并不会运行析构函数, 使用哪个实例由用户决定
132            core::ptr::read(self)
133        }
134    }
135}
136
137impl_tuples!();
138impl_trivial! {
139    (),
140    i8,
141    i16,
142    i32,
143    i64,
144    i128,
145    isize,
146    u8,
147    u16,
148    u32,
149    u64,
150    u128,
151    f32,
152    f64,
153    usize,
154    bool,
155    char,
156    NonZeroI8,
157    NonZeroI16,
158    NonZeroI32,
159    NonZeroI64,
160    NonZeroI128,
161    NonZeroIsize,
162    NonZeroU8,
163    NonZeroU16,
164    NonZeroU32,
165    NonZeroU64,
166    NonZeroU128,
167    NonZeroUsize,
168    PhantomData<T> [T: ?Sized],
169    PhantomPinned,
170    &T [T: ?Sized],
171    *mut T [T: ?Sized],
172    *const T [T: ?Sized],
173    NonNull<T> [T: ?Sized],
174    cmp::Ordering,
175    core::sync::atomic::Ordering,
176    Rc<T> [T],
177    Arc<T> [T],
178}
179impl_take! {
180    Vec<T> [T],
181    VecDeque<T> [T],
182    LinkedList<T> [T],
183    BTreeSet<T> [T],
184    BTreeMap<K, V> [K, V],
185    BinaryHeap<T> [T: Ord],
186    Option<T> [T],
187    String,
188    CString,
189    Poll<T> [T] { Poll::Pending },
190}
191#[cfg(feature = "std")]
192impl_take! {
193    HashSet<T, S> [T, S: Default],
194    HashMap<K, V, S> [K, V, S: Default],
195    OsString,
196    PathBuf,
197}
198
199/// Like C++ `std::move` use `&mut impl StdMove`
200///
201/// # Examples
202///
203/// Move resource types
204///
205/// ```
206/// # use std_move::r#move;
207/// let mut a = vec![1, 2, 3];
208/// let b;
209/// b = r#move!(a);
210/// assert_eq!(a, []);
211/// assert_eq!(b, [1, 2, 3]);
212/// ```
213///
214/// Trivial types
215///
216/// ```
217/// # use std_move::r#move;
218/// let mut n = 3;
219/// assert_eq!(r#move!(n), 3);
220/// assert_eq!(r#move!(n), 3);
221/// assert_eq!(n, 3);
222/// ```
223#[macro_export]
224macro_rules! r#move {
225    ($e:expr) => {
226        $crate::StdMove::std_move(&mut $e)
227    };
228}
229
230#[test]
231fn it_works() {
232    let mut a = vec![1, 2, 3];
233    let b;
234    b = r#move!(a);
235    assert_eq!(a, []);
236    assert_eq!(b, [1, 2, 3]);
237
238    let mut n = 3;
239    assert_eq!(r#move!(n), 3);
240    assert_eq!(r#move!(n), 3);
241    assert_eq!(n, 3);
242}
243
244#[test]
245fn move_maybe_uninit() {
246    let mut a = MaybeUninit::new(vec![1, 2, 3]);
247    let b = r#move!(a);
248    assert_eq!(unsafe { b.assume_init() }, [1, 2, 3]);
249}