swap3/
lib.rs

1//! # swap3
2//!
3//! Provides utility functions for simultaneously swapping three values by rotating them
4//! either left (`abc` → `bca`) or right (`abc` → `cab`). These functions can come in handy e.g.
5//! when rotating elements of a binary tree in list representation.
6//!
7//! The provided functions work on arbitrary types and do *not* require the type to be [`Clone`], [`Copy`]
8//! or [`Default`].
9//!
10//! ## Crate features
11//!
12//! * `unsafe` - The `unsafe` feature enables the use of (potentially faster) unsafe code.
13//!              It is disabled by default; when disabled, `forbid(unsafe_code)` is implied.
14//!
15//! ## Examples
16//!
17//! For individual references, the [`swap3_bca`] (rotate left) and [`swap3_cab`] (rotate right)
18//! functions are available:
19//!
20//! ```
21//! let mut a = 10;
22//! let mut b = 20;
23//! let mut c = 30;
24//!
25//! swap3::swap3_bca(&mut a, &mut b, &mut c);
26//! assert_eq!([a, b, c], [20, 30, 10]);
27//! ```
28//!
29//! For slices, the [`swap3_bca_slice`] and [`swap3_cab_slice`] functions can be used:
30//!
31//! ```
32//! let mut vec = vec![10, 20, 30, 40, 50, 60];
33//! swap3::swap3_bca_slice(&mut vec, 0, 1, 4);
34//! assert_eq!(vec, &[20, 50, 30, 40, 10, 60]);
35//! ```
36//!
37//! ... or using the [`Swap3`] trait imported from the prelude:
38//!
39//! ```
40//! use swap3::prelude::*;
41//!
42//! let mut vec = vec![10, 20, 30, 40, 50, 60];
43//! vec.swap3_bca(0, 1, 4);
44//! assert_eq!(vec, &[20, 50, 30, 40, 10, 60]);
45//! ```
46
47// SPDX-FileCopyrightText: 2023 Markus Mayer
48// SPDX-License-Identifier: MIT
49
50#![cfg_attr(feature = "unsafe", allow(unsafe_code))]
51#![cfg_attr(not(feature = "unsafe"), forbid(unsafe_code))]
52// only enables the `doc_cfg` feature when
53// the `docsrs` configuration attribute is defined
54#![cfg_attr(docsrs, feature(doc_cfg))]
55
56/// Provides simple access to commonly used traits.
57pub mod prelude {
58    pub use crate::Swap3;
59}
60
61/// Rotates three values to the left.
62///
63/// ## Arguments
64///
65/// * `a` - The first value, to be assigned with the value of `b`.
66/// * `b` - The second value, to be assigned with the value of `c`.
67/// * `c` - The third value, to be assigned with the value of `a`.
68///
69/// ## Example
70///
71/// ```
72/// let mut a = 10;
73/// let mut b = 20;
74/// let mut c = 30;
75/// swap3::swap3_bca(&mut a, &mut b, &mut c);
76/// assert_eq!([a, b, c], [20, 30, 10]);
77/// ```
78pub fn swap3_bca<T>(a: &mut T, b: &mut T, c: &mut T) {
79    std::mem::swap(a, b);
80    std::mem::swap(b, c);
81}
82
83/// Rotates three values to the right.
84///
85/// ## Arguments
86///
87/// * `a` - The first value, to be assigned with the value of `c`.
88/// * `b` - The second value, to be assigned with the value of `a`.
89/// * `c` - The third value, to be assigned with the value of `b`.
90///
91/// ## Example
92///
93/// ```
94/// let mut a = 10;
95/// let mut b = 20;
96/// let mut c = 30;
97/// swap3::swap3_cab(&mut a, &mut b, &mut c);
98/// assert_eq!([a, b, c], [30, 10, 20]);
99/// ```
100pub fn swap3_cab<T>(a: &mut T, b: &mut T, c: &mut T) {
101    std::mem::swap(a, c);
102    std::mem::swap(b, c);
103}
104
105/// Rotates three values to the left.
106///
107/// ## Arguments
108///
109/// * `data` - The slice whose elements to swap.
110/// * `a` - The first index, to be assigned with the value of `data[b]`.
111/// * `b` - The second index, to be assigned with the value of `data[c]`.
112/// * `c` - The third index, to be assigned with the value of `data[a]`.
113///
114/// ## Example
115///
116/// ```
117/// let mut vec = vec![50, 10, 90, 25, 30, 75];
118/// swap3::swap3_bca_slice(&mut vec, 0, 1, 4);
119/// assert_eq!(vec, &[10, 30, 90, 25, 50, 75]);
120/// ```
121#[inline(always)]
122pub fn swap3_bca_slice<T>(data: &mut [T], a: usize, b: usize, c: usize) {
123    #[cfg(feature = "unsafe")]
124    slice::bca_unsafe(data, a, b, c);
125    #[cfg(not(feature = "unsafe"))]
126    slice::bca_safe(data, a, b, c);
127}
128
129/// Rotates three values to the right.
130///
131/// ## Arguments
132///
133/// * `data` - The slice whose elements to swap.
134/// * `a` - The first index, to be assigned with the value of `data[c]`.
135/// * `b` - The second index, to be assigned with the value of `data[a]`.
136/// * `c` - The third index, to be assigned with the value of `data[b]`.
137///
138/// ## Example
139///
140/// ```
141/// let mut vec = vec![50, 10, 90, 25, 30, 75];
142/// swap3::swap3_bca_slice(&mut vec, 0, 1, 4);
143/// assert_eq!(vec, &[10, 30, 90, 25, 50, 75]);
144/// ```
145#[inline(always)]
146pub fn swap3_cab_slice<T>(data: &mut [T], a: usize, b: usize, c: usize) {
147    #[cfg(feature = "unsafe")]
148    slice::cab_unsafe(data, a, b, c);
149    #[cfg(not(feature = "unsafe"))]
150    slice::cab_safe(data, a, b, c);
151}
152
153/// Trait providing the [`Swap3::swap3_bca`] and [`Swap3::swap3_cab`] functions directly.
154pub trait Swap3<I = usize> {
155    /// Rotates three values to the left.
156    ///
157    /// ## Arguments
158    ///
159    /// * `a` - The first index, to be assigned with the value of `data[b]`.
160    /// * `b` - The second index, to be assigned with the value of `data[c]`.
161    /// * `c` - The third index, to be assigned with the value of `data[a]`.
162    ///
163    /// ## Example
164    ///
165    /// ```
166    /// use swap3::prelude::*;
167    /// let mut vec = vec![50, 10, 90, 25, 30, 75];
168    /// vec.swap3_bca(0, 1, 4);
169    /// assert_eq!(vec, &[10, 30, 90, 25, 50, 75]);
170    /// ```
171    fn swap3_bca(&mut self, a: I, b: I, c: I);
172
173    /// Rotates three values to the right.
174    ///
175    /// ## Arguments
176    ///
177    /// * `a` - The first index, to be assigned with the value of `data[c]`.
178    /// * `b` - The second index, to be assigned with the value of `data[a]`.
179    /// * `c` - The third index, to be assigned with the value of `data[b]`.
180    ///
181    /// ## Example
182    ///
183    /// ```
184    /// use swap3::prelude::*;
185    /// let mut vec = vec![50, 10, 90, 25, 30, 75];
186    /// vec.swap3_cab(0, 1, 4);
187    /// assert_eq!(vec, &[30, 50, 90, 25, 10, 75]);
188    /// ```
189    fn swap3_cab(&mut self, a: I, b: I, c: I);
190}
191
192impl<T> Swap3<usize> for [T] {
193    fn swap3_bca(&mut self, a: usize, b: usize, c: usize) {
194        swap3_bca_slice(self, a, b, c)
195    }
196
197    fn swap3_cab(&mut self, a: usize, b: usize, c: usize) {
198        swap3_cab_slice(self, a, b, c)
199    }
200}
201
202pub mod slice {
203    /// Rotates three values to the left.
204    ///
205    /// ## Arguments
206    ///
207    /// * `data` - The slice whose elements to swap.
208    /// * `a` - The first index, to be assigned with the value of `data[b]`.
209    /// * `b` - The second index, to be assigned with the value of `data[c]`.
210    /// * `c` - The third index, to be assigned with the value of `data[a]`.
211    ///
212    /// ## Example
213    ///
214    /// ```
215    /// let mut vec = vec![50, 10, 90, 25, 30, 75];
216    /// swap3::slice::bca_safe(&mut vec, 0, 1, 4);
217    /// assert_eq!(vec, &[10, 30, 90, 25, 50, 75]);
218    /// ```
219    #[inline(always)]
220    pub fn bca_safe<T>(data: &mut [T], a: usize, b: usize, c: usize) {
221        data.swap(a, b);
222        data.swap(b, c);
223    }
224
225    /// Rotates three values to the left.
226    ///
227    /// ## Arguments
228    ///
229    /// * `data` - The slice whose elements to swap.
230    /// * `a` - The first index, to be assigned with the value of `data[b]`.
231    /// * `b` - The second index, to be assigned with the value of `data[c]`.
232    /// * `c` - The third index, to be assigned with the value of `data[a]`.
233    ///
234    /// ## Example
235    ///
236    /// ```
237    /// let mut vec = vec![50, 10, 90, 25, 30, 75];
238    /// swap3::slice::bca_unsafe(&mut vec, 0, 1, 4);
239    /// assert_eq!(vec, &[10, 30, 90, 25, 50, 75]);
240    /// ```
241    #[cfg_attr(docsrs, doc(cfg(feature = "unsafe")))]
242    #[cfg(feature = "unsafe")]
243    #[inline(always)]
244    pub fn bca_unsafe<T>(data: &mut [T], a: usize, b: usize, c: usize) {
245        use std::ptr;
246
247        // SPDX-SnippetBegin
248        // SDPX—SnippetName: Adjusted slice::swap() from the Rust core library.
249        // SPDX-SnippetCopyrightText: The Rust Core Library authors
250        // SPDX-SnippetContributor: Adjusted by Markus Mayer for three arguments.
251        // SPDX-License-Identifier: MIT
252
253        let pa = ptr::addr_of_mut!(data[a]);
254        let pb = ptr::addr_of_mut!(data[b]);
255        let pc = ptr::addr_of_mut!(data[c]);
256        // SAFETY: `pa`, `pb` and `pc` have been created from safe mutable references and refer
257        // to elements in the slice and therefore are guaranteed to be valid and aligned.
258        // Note that accessing the elements behind `a`, `b` and `c` is checked and will
259        // panic when out of bounds.
260        unsafe {
261            ptr::swap(pa, pb);
262            ptr::swap(pb, pc);
263            // ptr::swap_nonoverlapping(pa, pb, 1);
264            // ptr::swap_nonoverlapping(pb, pc, 1);
265        }
266
267        // SPDX-SnippetEnd
268    }
269
270    /// Rotates three values to the right.
271    ///
272    /// ## Arguments
273    ///
274    /// * `data` - The slice whose elements to swap.
275    /// * `a` - The first index, to be assigned with the value of `data[c]`.
276    /// * `b` - The second index, to be assigned with the value of `data[a]`.
277    /// * `c` - The third index, to be assigned with the value of `data[b]`.
278    ///
279    /// ## Example
280    ///
281    /// ```
282    /// let mut vec = vec![50, 10, 90, 25, 30, 75];
283    /// swap3::slice::cab_safe(&mut vec, 0, 1, 4);
284    /// assert_eq!(vec, &[30, 50, 90, 25, 10, 75]);
285    /// ```
286    #[inline(always)]
287    pub fn cab_safe<T>(data: &mut [T], a: usize, b: usize, c: usize) {
288        data.swap(a, c);
289        data.swap(b, c);
290    }
291
292    /// Rotates three values to the left.
293    ///
294    /// ## Arguments
295    ///
296    /// * `data` - The slice whose elements to swap.
297    /// * `a` - The first index, to be assigned with the value of `data[b]`.
298    /// * `b` - The second index, to be assigned with the value of `data[c]`.
299    /// * `c` - The third index, to be assigned with the value of `data[a]`.
300    ///
301    /// ## Example
302    ///
303    /// ```
304    /// let mut vec = vec![50, 10, 90, 25, 30, 75];
305    /// swap3::slice::cab_unsafe(&mut vec, 0, 1, 4);
306    /// assert_eq!(vec, &[30, 50, 90, 25, 10, 75]);
307    /// ```
308    #[cfg_attr(docsrs, doc(cfg(feature = "unsafe")))]
309    #[cfg(feature = "unsafe")]
310    #[inline(always)]
311    pub fn cab_unsafe<T>(data: &mut [T], a: usize, b: usize, c: usize) {
312        use std::ptr;
313
314        // SPDX-SnippetBegin
315        // SDPX—SnippetName: Adjusted slice::swap() from the Rust core library.
316        // SPDX-SnippetCopyrightText: The Rust Core Library authors
317        // SPDX-SnippetContributor: Adjusted by Markus Mayer for three arguments.
318        // SPDX-License-Identifier: MIT
319
320        let pa = ptr::addr_of_mut!(data[a]);
321        let pb = ptr::addr_of_mut!(data[b]);
322        let pc = ptr::addr_of_mut!(data[c]);
323        // SAFETY: `pa`, `pb` and `pc` have been created from safe mutable references and refer
324        // to elements in the slice and therefore are guaranteed to be valid and aligned.
325        // Note that accessing the elements behind `a`, `b` and `c` is checked and will
326        // panic when out of bounds.
327        unsafe {
328            ptr::swap(pa, pc);
329            ptr::swap(pb, pc);
330            // ptr::swap_nonoverlapping(pa, pb, 1);
331            // ptr::swap_nonoverlapping(pb, pc, 1);
332        }
333
334        // SPDX-SnippetEnd
335    }
336}
337
338#[cfg(test)]
339mod tests {
340    use super::*;
341
342    #[test]
343    fn test_swap3_bca() {
344        let mut a = 65;
345        let mut b = 66;
346        let mut c = 67;
347        swap3_bca(&mut a, &mut b, &mut c);
348        assert_eq!([a, b, c], [66, 67, 65]);
349    }
350
351    #[test]
352    fn test_swap3_cab() {
353        let mut a = 65;
354        let mut b = 66;
355        let mut c = 67;
356        swap3_cab(&mut a, &mut b, &mut c);
357        assert_eq!([a, b, c], [67, 65, 66]);
358    }
359
360    #[test]
361    fn test_swap3_bca_vec() {
362        let mut vec = vec![50, 10, 90, 25, 30, 75];
363        slice::bca_safe(&mut vec, 0, 1, 4);
364        assert_eq!(vec, &[10, 30, 90, 25, 50, 75]);
365    }
366
367    #[test]
368    #[cfg(feature = "unsafe")]
369    fn test_swap3_bca_vec_unsafe() {
370        let mut vec = vec![50, 10, 90, 25, 30, 75];
371        slice::bca_unsafe(&mut vec, 0, 1, 4);
372        assert_eq!(vec, &[10, 30, 90, 25, 50, 75]);
373    }
374
375    #[test]
376    fn test_swap3_cab_vec() {
377        let mut vec = vec![50, 10, 90, 25, 30, 75];
378        slice::cab_safe(&mut vec, 0, 1, 4);
379        assert_eq!(vec, &[30, 50, 90, 25, 10, 75]);
380    }
381
382    #[test]
383    #[cfg(feature = "unsafe")]
384    fn test_swap3_cab_vec_unsafe() {
385        let mut vec = vec![50, 10, 90, 25, 30, 75];
386        slice::cab_unsafe(&mut vec, 0, 1, 4);
387        assert_eq!(vec, &[30, 50, 90, 25, 10, 75]);
388    }
389
390    #[test]
391    fn test_vec_trait_bca() {
392        let mut vec = vec![50, 10, 90, 25, 30, 75];
393        vec.swap3_bca(0, 1, 4);
394        assert_eq!(vec, &[10, 30, 90, 25, 50, 75]);
395    }
396
397    #[test]
398    fn test_array_trait_cab() {
399        let mut vec = [50, 10, 90, 25, 30, 75];
400        vec.swap3_cab(0, 1, 4);
401        assert_eq!(vec, [30, 50, 90, 25, 10, 75]);
402    }
403}