1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use std::marker::PhantomData;
use crate::{
    alloc::Alloc,
    Handle,
};

mod traits;
mod iter;
mod implementation;

pub use iter::*;

/// Imitates a [`std::vec::Vec`] of a slice-based DST. All values have the
/// same slice length, which allows random-access. Guarantied to store all
/// values inline in the same allocation (sequentially), only using extra
/// space for inherent alignment-padding. The trade-off is that the
/// slice-lengths of the dynamically sized tail must all be the same, and is
/// stored alongside the pointer to the allocation/length/capacity. Thus, this
/// [`Vec`] is 4-words instead of 3-words.
///
/// # Panics / Aborts
///
/// Any operation that may increase the capacity will abort if there is a
/// failure to allocate, or panic if the [`usize`] math overflows beforehand.
///
/// # Uses
///
/// If your application knows at compile-time the length of a slice, you
/// should use `Vec<(T, [S; LENGTH])>`. Read no further.
///
/// However, the length may not be known until runtime. In this scenario, a
/// `Vec<(T, Vec<S>)>` or `Vec<(T, Box<[S]>)>` should be used instead, the
/// latter verifiably not wasting any space.
///
/// In the case of the length only known at runtime (like reading in columns
/// of a `.csv` file), those solutions may show evidence of degraded
/// performance from the random memory access patterns of said pointers. By
/// opting to use this implementation, there is a guaranty that all of the
/// data is contained in a single allocation, as-is the case of the
/// constant-length slice. Some applications may receive a performance benefit
/// by arranging the data in this way, while others may lose performance from
/// the overhead of this implementation.
///
/// # Usage
///
/// ```rust
/// use dst::FixedVec;
///
/// let mut vec = FixedVec::<Option<&str>, usize>::new(4);
/// vec.push_default();
/// let item = vec.get(0).unwrap();
/// assert_eq!(item.value, None);
/// assert_eq!(item.tail, [0, 0, 0, 0]);
///
/// vec.push(Some("Name"), [1, 2, 3, 4].iter().copied());
/// let item = vec.get(1).unwrap();
/// assert_eq!(item.value, Some("Name"));
/// assert_eq!(item.tail, [1, 2, 3, 4]);
/// ```

pub struct Vec<T, S> {
    ptr: Alloc,
    length: usize,
    slice: usize,
    _phantom: PhantomData<Handle<T, [S]>>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum RemovalMode {
    /// Shifts entire tail to cover
    Shift,
    /// Reorders with the tail
    Replace,
}

#[cfg(test)]
mod test {
    use super::*;

    #[fn_fixture::snapshot("snapshot-tests/csv")]
    fn csv_to_vec(file: &str) -> Vec<(), &str> {
        let columns = file.lines().next().unwrap().split(',').count();

        let mut vec = Vec::new(columns);
        for line in file.lines().skip(1) {
            let line = line.trim_end();
            vec.push((), line.split(','));
        }
        vec
    }
}