vec_dimension_shift/lib.rs
1//! [![github]](https://github.com/usagi/vec-dimension-shift) [![crates-io]](https://crates.io/crates/vec-dimension-shift) [![docs-rs]](https://docs.rs/vec-dimension-shift)<br>
2//! [](https://travis-ci.org/usagi/vec-dimension-shift)
3//!
4//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
5//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
6//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
7//!
8//! # Vec Dimension Shift
9//!
10//! This crate is an extension for `Vec<T>` that extends the dimension-shift features.
11//!
12//! Note: vec-dimension-shift crate use an unsafe features in the internal details. As an alternative, [dimension_shift_buffer][] is available if you want a more flexible runtime dimension shifting or safe-only implementation.
13//!
14//! [dimension_shift_buffer]: https://crates.io/crates/dimension_shiftable_buffer
15//!
16//! ## What's the "dimension shift"?
17//!
18//! In basically,
19//!
20//! - `Vec<f64>` --( Dimension shift, to the 2-dimension! )--> `Vec<[f64;2]>`
21//! - Original datum type is `f64` ≈ `[f64;1]`, 2D-shifted datum type is `[f64;2]`.
22//! - Original datum element type is `f64`, 2D-shifted datum element type is `f64`.
23//! - All datum elements were preserved.
24//! - `Vec<[f64;2]>` --( Dimension shift, flatten! )--> `Vec<f64>`
25//! - Of course, it's same too.
26//!
27//! ## Implemented features
28//!
29//! 1. `VecDimensionShift2D`, `VecDimensionShift2DFlatten` and the 2..16-dimension `trait`s for `Vec<T>`.
30//! 2. `make_vec_dimension_shift_n_dimension!` macro for make your desired N-dimension `trait`s.
31//!
32//! Note: In the default, 2D, 3D, 4D version of `VecDimensionShift?D` is enabled. Set `default-features=false` if you don't need these.
33//!
34//! ## Example
35//!
36//! ```toml
37//! [dependencies]
38//! vec-dimension-shift = "*"
39//! ```
40//!
41//! ### Example-1
42//!
43//! 1D -> 2D -> 1D -> 3D -> 1D, and modify an element:
44//!
45//! ```rust
46//! use vec_dimension_shift::{
47//! VecDimensionShift2D,
48//! VecDimensionShift2DFlatten,
49//! VecDimensionShift3D,
50//! VecDimensionShift3DFlatten
51//! };
52//!
53//! fn d2_and_d3()
54//! {
55//! let original = vec![0.0, 1.1, 2.2, 3.3, 4.4, 5.5];
56//! dbg!(&original);
57//!
58//! let mut d2_shifted = original.as_2d_array().unwrap();
59//! dbg!(&d2_shifted);
60//! assert_eq!(d2_shifted[0], [0.0, 1.1]);
61//! assert_eq!(d2_shifted[1], [2.2, 3.3]);
62//! assert_eq!(d2_shifted[2], [4.4, 5.5]);
63//! d2_shifted[1][1] = -1.0;
64//!
65//! let flatten = d2_shifted.as_flatten();
66//! dbg!(&flatten);
67//!
68//! let mut d3_shifted = flatten.as_3d_array().unwrap();
69//! dbg!(&d3_shifted);
70//! assert_eq!(d3_shifted[0], [0.0, 1.1, 2.2]);
71//! assert_eq!(d3_shifted[1], [-1.0, 4.4, 5.5]);
72//! d3_shifted[1][1] = -2.0;
73//!
74//! let flatten = d3_shifted.as_flatten();
75//! dbg!(&flatten);
76//!
77//! assert_eq!(flatten, vec![0.0, 1.1, 2.2, -1.0, -2.0, 5.5])
78//! }
79//! ```
80//!
81//! ### Example-2
82//!
83//! 1. Make `trait`s just you needs (eg, 2D and 3D)
84//! 2. -> Make 1D * 12-length buffer
85//! 3. -> Shift the dimension to 2D * 6-length buffer
86//! 4. -> Shift the dimension to ( 2D * 3D ) * 2-length buffer
87//!
88//! ```rust
89//! use vec_dimension_shift::make_vec_dimension_shift_n_dimension;
90//!
91//! fn n_dimension_macro_generator()
92//! {
93//! make_vec_dimension_shift_n_dimension! { VecDimensionShift2D, VecDimensionShift2DFlatten, as_2d_array_no_check, to_2d_array_no_check, as_2d_array, to_2d_array, as_2d_array_truncate, to_2d_array_truncate, as_2d_array_padding, to_2d_array_padding, 2 }
94//! make_vec_dimension_shift_n_dimension! { VecDimensionShift3D, VecDimensionShift3DFlatten, as_3d_array_no_check, to_3d_array_no_check, as_3d_array, to_3d_array, as_3d_array_truncate, to_3d_array_truncate, as_3d_array_padding, to_3d_array_padding, 3 }
95//!
96//! let original = vec![0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10, 11.11];
97//! dbg!(&original);
98//!
99//! let d2 = original.as_2d_array().unwrap();
100//! assert_eq!(d2[0], [0.0, 1.1]);
101//! assert_eq!(d2[1], [2.2, 3.3]);
102//! assert_eq!(d2[2], [4.4, 5.5]);
103//! assert_eq!(d2[3], [6.6, 7.7]);
104//! assert_eq!(d2[4], [8.8, 9.9]);
105//! assert_eq!(d2[5], [10.10, 11.11]);
106//! dbg!(&d2);
107//!
108//! let d3 = d2.as_3d_array().unwrap();
109//! assert_eq!(d3[0], [[0.0, 1.1], [2.2, 3.3], [4.4, 5.5]]);
110//! assert_eq!(d3[1], [[6.6, 7.7], [8.8, 9.9], [10.10, 11.11]]);
111//! dbg!(&d3);
112//! }
113//! ```
114//!
115//! More details and examples are exists in the [README.md][] and [examples/] and [tests/].
116//!
117//! [README.md]: https://github.com/usagi/vec-dimension-shift
118//! [examples/]: https://github.com/usagi/vec-dimension-shift/blob/master/examples
119//! [tests/]: https://github.com/usagi/vec-dimension-shift/blob/master/tests
120//!
121
122#[cfg(feature = "d2")]
123make_vec_dimension_shift_n_dimension! { VecDimensionShift2D, VecDimensionShift2DFlatten, as_2d_array_no_check, to_2d_array_no_check, as_2d_array, to_2d_array, as_2d_array_truncate, to_2d_array_truncate, as_2d_array_padding, to_2d_array_padding, 2 }
124#[cfg(feature = "d3")]
125make_vec_dimension_shift_n_dimension! { VecDimensionShift3D, VecDimensionShift3DFlatten, as_3d_array_no_check, to_3d_array_no_check, as_3d_array, to_3d_array, as_3d_array_truncate, to_3d_array_truncate, as_3d_array_padding, to_3d_array_padding, 3 }
126#[cfg(feature = "d4")]
127make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift4DFlatten, as_4d_array_no_check, to_4d_array_no_check, as_4d_array, to_4d_array, as_4d_array_truncate, to_4d_array_truncate, as_4d_array_padding, to_4d_array_padding, 4 }
128#[cfg(feature = "d5")]
129make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift5DFlatten, as_5d_array_no_check, to_5d_array_no_check, as_5d_array, to_5d_array, as_5d_array_truncate, to_5d_array_truncate, as_5d_array_padding, to_5d_array_padding, 4 }
130#[cfg(feature = "d6")]
131make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift6DFlatten, as_6d_array_no_check, to_6d_array_no_check, as_6d_array, to_6d_array, as_6d_array_truncate, to_6d_array_truncate, as_6d_array_padding, to_6d_array_padding, 4 }
132#[cfg(feature = "d7")]
133make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift7DFlatten, as_7d_array_no_check, to_7d_array_no_check, as_7d_array, to_7d_array, as_7d_array_truncate, to_7d_array_truncate, as_7d_array_padding, to_7d_array_padding, 4 }
134#[cfg(feature = "d8")]
135make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift8DFlatten, as_8d_array_no_check, to_8d_array_no_check, as_8d_array, to_8d_array, as_8d_array_truncate, to_8d_array_truncate, as_8d_array_padding, to_8d_array_padding, 4 }
136#[cfg(feature = "d9")]
137make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift9DFlatten, as_9d_array_no_check, to_9d_array_no_check, as_9d_array, to_9d_array, as_9d_array_truncate, to_9d_array_truncate, as_9d_array_padding, to_9d_array_padding, 4 }
138#[cfg(feature = "d10")]
139make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift10DFlatten, as_10d_array_no_check, to_10d_array_no_check, as_10d_array, to_10d_array, as_10d_array_truncate, to_10d_array_truncate, as_10d_array_padding, to_10d_array_padding, 4 }
140#[cfg(feature = "d11")]
141make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift11DFlatten, as_11d_array_no_check, to_11d_array_no_check, as_11d_array, to_11d_array, as_11d_array_truncate, to_11d_array_truncate, as_11d_array_padding, to_11d_array_padding, 4 }
142#[cfg(feature = "d12")]
143make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift12DFlatten, as_12d_array_no_check, to_12d_array_no_check, as_12d_array, to_12d_array, as_12d_array_truncate, to_12d_array_truncate, as_12d_array_padding, to_12d_array_padding, 4 }
144#[cfg(feature = "d13")]
145make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift13DFlatten, as_13d_array_no_check, to_13d_array_no_check, as_13d_array, to_13d_array, as_13d_array_truncate, to_13d_array_truncate, as_13d_array_padding, to_13d_array_padding, 4 }
146#[cfg(feature = "d14")]
147make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift14DFlatten, as_14d_array_no_check, to_14d_array_no_check, as_14d_array, to_14d_array, as_14d_array_truncate, to_14d_array_truncate, as_14d_array_padding, to_14d_array_padding, 4 }
148#[cfg(feature = "d15")]
149make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift15DFlatten, as_15d_array_no_check, to_15d_array_no_check, as_15d_array, to_15d_array, as_15d_array_truncate, to_15d_array_truncate, as_15d_array_padding, to_15d_array_padding, 4 }
150#[cfg(feature = "d16")]
151make_vec_dimension_shift_n_dimension! { VecDimensionShift4D, VecDimensionShift16DFlatten, as_16d_array_no_check, to_16d_array_no_check, as_16d_array, to_16d_array, as_16d_array_truncate, to_16d_array_truncate, as_16d_array_padding, to_16d_array_padding, 4 }
152
153/// This is the `trait` generator. If you need the N-dimension version, then use it.
154/// (Note: 2D, 3D, 4D are available on the features. )
155/// ## Usage
156/// Code:
157/// ```rust,ignore
158/// make_vec_dimension_shift_n_dimension! { VecDimensionShift2D, VecDimensionShift2DFlatten, as_2d_array_no_check, to_2d_array_no_check, as_2d_array, to_2d_array, as_2d_array_truncate, to_2d_array_truncate, as_2d_array_padding, to_2d_array_padding, 2 }
159/// ```
160/// Then you will get the `VecDimensionShift2D` trait.
161/// Thus, you can use the dimension shift implements such as:
162/// ```rust,ignore
163/// let my_vec = vec![0,1,2,3,4,5];
164/// println!("my_vec is: {}", my_vec);
165/// let my_2d_shifted = my_vec.as_2d_array().unwrap();
166/// println!("my_2d_view is: {}", my_2d_view);
167/// let my_flatten = my_2d_shifted.as_flatten();
168/// println!("my_flatten is: {}", my_flatten);
169/// let my_3d_view = my_flatten.as_3d_array().unwrap();
170/// println!("my_3d_view is: {}", my_3d_view);
171/// ```
172/// It can be simplify if the `#![feature(concat_idents)]` to stable, maybe.
173#[macro_export]
174macro_rules! make_vec_dimension_shift_n_dimension {
175 (
176 $trait_symbol:ident,
177 $trait_flatten_symbol:ident,
178 $as_nc:ident,
179 $to_nc:ident,
180 $as_c:ident,
181 $to_c:ident,
182 $as_truncate:ident,
183 $to_truncate:ident,
184 $as_padding:ident,
185 $to_padding:ident,
186 $dimension:expr
187 ) => {
188 pub trait $trait_flatten_symbol<T>
189 {
190 fn as_flatten(self) -> Vec<T>;
191 }
192 impl<T> $trait_flatten_symbol<T> for Vec<[T; $dimension]>
193 {
194 fn as_flatten(self) -> Vec<T>
195 {
196 const ADDRESS_OFFSET_OF_VEC_SIZE: usize = 2;
197 let flatten_len = $dimension * self.len();
198 let r: Vec<T> = unsafe { std::mem::transmute(self) };
199 let r_ptr: *const usize = unsafe { std::mem::transmute(&r) };
200 let r_len_ptr: usize = r_ptr as usize + ADDRESS_OFFSET_OF_VEC_SIZE * std::mem::size_of::<usize>();
201 let r_len_ptr: *mut usize = unsafe { std::mem::transmute(r_len_ptr) };
202 unsafe {
203 std::ptr::write(r_len_ptr, flatten_len);
204 }
205 r
206 }
207 }
208 pub trait $trait_symbol<T>
209 {
210 fn $as_nc(self) -> Vec<[T; $dimension]>;
211 fn $to_nc(&self) -> Vec<[T; $dimension]>;
212 fn $as_c(self) -> Result<Vec<[T; $dimension]>, Vec<T>>;
213 fn $to_c(&self) -> Result<Vec<[T; $dimension]>, &Vec<T>>;
214 fn $as_truncate(self) -> Vec<[T; $dimension]>;
215 fn $to_truncate(&mut self) -> Vec<[T; $dimension]>;
216 fn $as_padding(self, v: T) -> Vec<[T; $dimension]>;
217 fn $to_padding(&mut self, v: T) -> Vec<[T; $dimension]>;
218 }
219 impl<T: Clone + Default> $trait_symbol<T> for Vec<T>
220 {
221 fn $as_nc(self) -> Vec<[T; $dimension]>
222 {
223 let mut r: Vec<[T; $dimension]> = unsafe { std::mem::transmute(self) };
224 r.truncate(r.len() / $dimension);
225 r
226 }
227
228 fn $to_nc(&self) -> Vec<[T; $dimension]>
229 {
230 let mut r: Vec<[T; $dimension]> = unsafe { std::ptr::read(self.as_ptr() as _) };
231 r.truncate(r.len() / $dimension);
232 r
233 }
234
235 fn $as_c(self) -> Result<Vec<[T; $dimension]>, Vec<T>>
236 {
237 const D: usize = $dimension;
238 match self.len() % D == 0
239 {
240 true => Ok(self.$as_nc()),
241 _ => Err(self)
242 }
243 }
244
245 fn $to_c(&self) -> Result<Vec<[T; $dimension]>, &Vec<T>>
246 {
247 const D: usize = $dimension;
248 match self.len() % D == 0
249 {
250 true => Ok(self.$to_nc()),
251 _ => Err(self)
252 }
253 }
254
255 fn $as_truncate(mut self) -> Vec<[T; $dimension]>
256 {
257 const D: usize = $dimension;
258 self.truncate(self.len() - self.len() % D);
259 self.$as_nc()
260 }
261
262 fn $to_truncate(&mut self) -> Vec<[T; $dimension]>
263 {
264 const D: usize = $dimension;
265 self.truncate(self.len() - self.len() % D);
266 self.$to_nc()
267 }
268
269 fn $as_padding(mut self, v: T) -> Vec<[T; $dimension]>
270 {
271 const D: usize = $dimension;
272 self.resize(self.len() + D - self.len() % D, v);
273 self.$as_nc()
274 }
275
276 fn $to_padding(&mut self, v: T) -> Vec<[T; $dimension]>
277 {
278 const D: usize = $dimension;
279 self.resize(self.len() + D - self.len() % D, v);
280 self.$to_nc()
281 }
282 }
283 };
284}