core_extensions/slices/slice_bias.rs
1/// What directions [`SliceExt`]`::{`[`slice_lossy`]`, `[`slice_lossy_mut`]`}` are biased towards.
2///
3/// For `str` this has the effect of going in those directions if
4/// the `start` and/or `end` bound is between char boundaries.
5///
6/// For `[T]` this has no effect and
7/// it is recommended to use `()` as a parameter instead
8/// (`()` is converted to [`SliceBias::OUT`](#associatedconstant.OUT)).
9///
10/// # Example
11///
12/// ### String
13///
14/// ```
15/// use core_extensions::SliceExt;
16/// use core_extensions::slices::SliceBias;
17///
18/// let word = "niño";
19///
20/// assert_eq!(
21/// word.char_indices().collect::<Vec<_>>(),
22/// &[(0, 'n'), (1, 'i'), (2, 'ñ'), (4, 'o')]
23/// );
24///
25/// assert_eq!(word.slice_lossy(0..1000, ()), word);
26/// assert_eq!(word.slice_lossy(10..10000, ()), "");
27/// assert_eq!(word.slice_lossy(0..4, ()), "niñ");
28/// assert_eq!(word.slice_lossy(0..3, ()), "niñ");
29/// assert_eq!(word.slice_lossy(0..2, ()), "ni");
30/// assert_eq!(word.slice_lossy(3..3, ()), "ñ");
31/// assert_eq!(word.slice_lossy(3..4, ()), "ñ");
32/// assert_eq!(word.slice_lossy(2..3, ()), "ñ");
33///
34/// assert_eq!(word.slice_lossy(0..1000, SliceBias::OUT), word);
35/// assert_eq!(word.slice_lossy(10..10000, SliceBias::OUT), "");
36/// assert_eq!(word.slice_lossy(0..4, SliceBias::OUT), "niñ");
37/// assert_eq!(word.slice_lossy(0..3, SliceBias::OUT), "niñ");
38/// assert_eq!(word.slice_lossy(0..2, SliceBias::OUT), "ni");
39/// assert_eq!(word.slice_lossy(3..3, SliceBias::OUT), "ñ");
40/// assert_eq!(word.slice_lossy(3..4, SliceBias::OUT), "ñ");
41/// assert_eq!(word.slice_lossy(2..3, SliceBias::OUT), "ñ");
42///
43/// assert_eq!(word.slice_lossy(0..10000, SliceBias::IN), word);
44/// assert_eq!(word.slice_lossy(10..10000, SliceBias::IN), "");
45/// assert_eq!(word.slice_lossy(0..4, SliceBias::IN), "niñ");
46/// assert_eq!(word.slice_lossy(0..3, SliceBias::IN), "ni");
47/// assert_eq!(word.slice_lossy(0..2, SliceBias::IN), "ni");
48/// assert_eq!(word.slice_lossy(3..3, SliceBias::IN), "");
49/// assert_eq!(word.slice_lossy(3..4, SliceBias::IN), "");
50/// assert_eq!(word.slice_lossy(2..3, SliceBias::IN), "");
51///
52/// assert_eq!(word.slice_lossy(0..1000, SliceBias::LEFT), word);
53/// assert_eq!(word.slice_lossy(10..10000, SliceBias::LEFT), "");
54/// assert_eq!(word.slice_lossy(0..4, SliceBias::LEFT), "niñ");
55/// assert_eq!(word.slice_lossy(0..3, SliceBias::LEFT), "ni");
56/// assert_eq!(word.slice_lossy(0..2, SliceBias::LEFT), "ni");
57/// assert_eq!(word.slice_lossy(3..3, SliceBias::LEFT), "");
58/// assert_eq!(word.slice_lossy(3..4, SliceBias::LEFT), "ñ");
59/// assert_eq!(word.slice_lossy(2..3, SliceBias::LEFT), "");
60///
61/// assert_eq!(word.slice_lossy(0..1000, SliceBias::RIGHT), word);
62/// assert_eq!(word.slice_lossy(10..10000, SliceBias::RIGHT), "");
63/// assert_eq!(word.slice_lossy(0..4, SliceBias::RIGHT), "niñ");
64/// assert_eq!(word.slice_lossy(0..3, SliceBias::RIGHT), "niñ");
65/// assert_eq!(word.slice_lossy(0..2, SliceBias::RIGHT), "ni");
66/// assert_eq!(word.slice_lossy(3..3, SliceBias::RIGHT), "");
67/// assert_eq!(word.slice_lossy(3..4, SliceBias::RIGHT), "");
68/// assert_eq!(word.slice_lossy(2..3, SliceBias::RIGHT), "ñ");
69///
70///
71/// ```
72///
73/// [`SliceExt`]: ./trait.SliceExt.html
74/// [`slice_lossy`]: ./trait.SliceExt.html#tymethod.slice_lossy
75/// [`slice_lossy_mut`]: ./trait.SliceExt.html#tymethod.slice_lossy_mut
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub struct SliceBias {
78 /// bias of the start bound
79 pub start: BiasDirection,
80 /// bias of the end bound
81 pub end: BiasDirection,
82}
83
84/// The direction a range bound is moved towards to make the bound a valid index.
85#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub enum BiasDirection {
87 /// Means that the bound is biased to lower indices
88 Left,
89 /// Means that the bound is biased to higher indices
90 Right,
91}
92
93impl SliceBias {
94 /// Biased inwards, start bounds go right, end bounds go left.
95 pub const IN: Self = Self {
96 start: BiasDirection::Right,
97 end: BiasDirection::Left,
98 };
99 /// Biased outwards, start bounds go left, end bounds go right.
100 pub const OUT: Self = Self {
101 start: BiasDirection::Left,
102 end: BiasDirection::Right,
103 };
104 /// Biased leftwards, both bounds go left.
105 pub const LEFT: Self = Self {
106 start: BiasDirection::Left,
107 end: BiasDirection::Left,
108 };
109 /// Biased rightwards. both bounds go right.
110 pub const RIGHT: Self = Self {
111 start: BiasDirection::Right,
112 end: BiasDirection::Right,
113 };
114}
115
116/// Returns a [`SliceBias::OUT`](#associatedconstant.OUT)
117impl From<()> for SliceBias {
118 fn from(_: ()) -> Self {
119 Self::OUT
120 }
121}
122
123impl From<BiasDirection> for SliceBias {
124 fn from(dir: BiasDirection) -> Self {
125 Self {
126 start: dir,
127 end: dir,
128 }
129 }
130}
131
132impl From<(BiasDirection,)> for SliceBias {
133 fn from((dir,): (BiasDirection,)) -> Self {
134 Self {
135 start: dir,
136 end: dir,
137 }
138 }
139}
140
141impl From<(BiasDirection, BiasDirection)> for SliceBias {
142 fn from((start, end): (BiasDirection, BiasDirection)) -> Self {
143 Self { start, end }
144 }
145}
146
147#[cfg(test)]
148mod test {
149 use super::*;
150
151 use rand::{Rand, Rng};
152
153 impl Rand for SliceBias {
154 fn rand<R: Rng>(rng: &mut R) -> Self {
155 fn rand_dir<R: Rng>(rng: &mut R) -> BiasDirection {
156 match rng.gen_range::<u8>(0, 2) {
157 0 => BiasDirection::Left,
158 _=> BiasDirection::Right,
159 }
160 }
161
162 SliceBias{
163 start: rand_dir(rng),
164 end: rand_dir(rng),
165 }
166 }
167 }
168
169 #[test]
170 fn doc_comments() {
171 use SliceExt;
172 let word = "niño";
173
174 assert_eq!(word.slice_lossy(0..1000, SliceBias::OUT), word);
175 assert_eq!(word.slice_lossy(10..10000, SliceBias::OUT), "");
176 assert_eq!(word.slice_lossy(0..4, SliceBias::OUT), "niñ");
177 assert_eq!(word.slice_lossy(0..3, SliceBias::OUT), "niñ");
178 assert_eq!(word.slice_lossy(0..2, SliceBias::OUT), "ni");
179
180 assert_eq!(word.slice_lossy(0..10000, SliceBias::IN), word);
181 assert_eq!(word.slice_lossy(10..10000, SliceBias::IN), "");
182 assert_eq!(word.slice_lossy(0..4, SliceBias::IN), "niñ");
183 assert_eq!(word.slice_lossy(0..3, SliceBias::IN), "ni");
184 assert_eq!(word.slice_lossy(0..2, SliceBias::IN), "ni");
185 assert_eq!(word.slice_lossy(3..3, SliceBias::IN), "");
186 assert_eq!(word.slice_lossy(3..4, SliceBias::IN), "");
187 assert_eq!(word.slice_lossy(2..3, SliceBias::IN), "");
188
189 assert_eq!(word.slice_lossy(0..1000, SliceBias::LEFT), word);
190 assert_eq!(word.slice_lossy(10..10000, SliceBias::LEFT), "");
191 assert_eq!(word.slice_lossy(0..4, SliceBias::LEFT), "niñ");
192 assert_eq!(word.slice_lossy(0..3, SliceBias::LEFT), "ni");
193 assert_eq!(word.slice_lossy(0..2, SliceBias::LEFT), "ni");
194 assert_eq!(word.slice_lossy(3..3, SliceBias::LEFT), "");
195 assert_eq!(word.slice_lossy(3..4, SliceBias::LEFT), "ñ");
196 assert_eq!(word.slice_lossy(2..3, SliceBias::LEFT), "");
197
198 assert_eq!(word.slice_lossy(0..1000, SliceBias::RIGHT), word);
199 assert_eq!(word.slice_lossy(10..10000, SliceBias::RIGHT), "");
200 assert_eq!(word.slice_lossy(0..4, SliceBias::RIGHT), "niñ");
201 assert_eq!(word.slice_lossy(0..3, SliceBias::RIGHT), "niñ");
202 assert_eq!(word.slice_lossy(0..2, SliceBias::RIGHT), "ni");
203 assert_eq!(word.slice_lossy(3..3, SliceBias::RIGHT), "");
204 assert_eq!(word.slice_lossy(3..4, SliceBias::RIGHT), "");
205 assert_eq!(word.slice_lossy(2..3, SliceBias::RIGHT), "ñ");
206 }
207
208}