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}