1use crate::__private::{Input, text};
2use crate::Error;
3use core::fmt;
4use core::hash::{Hash, Hasher};
5use core::mem::MaybeUninit;
6use core::ops::{Deref, DerefMut};
7
8pub struct Values<T, const N: usize> {
26 items: [MaybeUninit<T>; N],
27 len: usize,
28}
29
30impl<T, const N: usize> Values<T, N> {
31 pub const fn new() -> Self {
33 Values {
34 items: [const { MaybeUninit::uninit() }; N],
35 len: 0,
36 }
37 }
38
39 pub const fn capacity(&self) -> usize {
41 N
42 }
43
44 pub fn push(&mut self, value: T) -> Result<(), T> {
46 if self.len == N {
47 return Err(value);
48 }
49 self.items[self.len].write(value);
50 self.len += 1;
51 Ok(())
52 }
53
54 pub fn as_slice(&self) -> &[T] {
56 unsafe { core::slice::from_raw_parts(self.items.as_ptr().cast::<T>(), self.len) }
57 }
58
59 pub fn as_mut_slice(&mut self) -> &mut [T] {
61 unsafe { core::slice::from_raw_parts_mut(self.items.as_mut_ptr().cast::<T>(), self.len) }
62 }
63}
64
65impl<T, const N: usize> Drop for Values<T, N> {
66 fn drop(&mut self) {
67 unsafe { core::ptr::drop_in_place(self.as_mut_slice()) }
68 }
69}
70
71impl<T, const N: usize> Default for Values<T, N> {
72 fn default() -> Self {
73 Self::new()
74 }
75}
76
77impl<T, const N: usize> Deref for Values<T, N> {
78 type Target = [T];
79
80 fn deref(&self) -> &[T] {
81 self.as_slice()
82 }
83}
84
85impl<T, const N: usize> DerefMut for Values<T, N> {
86 fn deref_mut(&mut self) -> &mut [T] {
87 self.as_mut_slice()
88 }
89}
90
91impl<T: Clone, const N: usize> Clone for Values<T, N> {
92 fn clone(&self) -> Self {
93 let mut clone = Self::new();
94 for value in self.iter() {
95 let _ = clone.push(value.clone());
96 }
97 clone
98 }
99}
100
101impl<T: fmt::Debug, const N: usize> fmt::Debug for Values<T, N> {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 f.debug_list().entries(self.iter()).finish()
104 }
105}
106
107impl<T: PartialEq<U>, U, const N: usize, const M: usize> PartialEq<Values<U, M>> for Values<T, N> {
108 fn eq(&self, other: &Values<U, M>) -> bool {
109 self.as_slice() == other.as_slice()
110 }
111}
112
113impl<T: Eq, const N: usize> Eq for Values<T, N> {}
114
115impl<T: PartialEq<U>, U, const N: usize> PartialEq<[U]> for Values<T, N> {
116 fn eq(&self, other: &[U]) -> bool {
117 self.as_slice() == other
118 }
119}
120
121impl<T: PartialEq<U>, U, const N: usize> PartialEq<&[U]> for Values<T, N> {
122 fn eq(&self, other: &&[U]) -> bool {
123 self.as_slice() == *other
124 }
125}
126
127impl<T: PartialEq<U>, U, const N: usize, const M: usize> PartialEq<[U; M]> for Values<T, N> {
128 fn eq(&self, other: &[U; M]) -> bool {
129 self.as_slice() == other
130 }
131}
132
133impl<T: Hash, const N: usize> Hash for Values<T, N> {
134 fn hash<H: Hasher>(&self, state: &mut H) {
135 self.as_slice().hash(state);
136 }
137}
138
139impl<'v, T, const N: usize> IntoIterator for &'v Values<T, N> {
140 type Item = &'v T;
141 type IntoIter = core::slice::Iter<'v, T>;
142
143 fn into_iter(self) -> Self::IntoIter {
144 self.iter()
145 }
146}
147
148impl<'v, T, const N: usize> IntoIterator for &'v mut Values<T, N> {
149 type Item = &'v mut T;
150 type IntoIter = core::slice::IterMut<'v, T>;
151
152 fn into_iter(self) -> Self::IntoIter {
153 self.iter_mut()
154 }
155}
156
157#[doc(hidden)]
158#[diagnostic::on_unimplemented(
159 message = "`{Self}` cannot collect repeated argument values",
160 label = "unsupported collection type",
161 note = "use `getargs_derive::Values<T, N>`, `heapless::Vec<T, N>` with the `heapless` feature of `getargs-derive`, or `Vec<T>` with its `alloc` feature"
162)]
163pub trait Collection: Sized {
164 type Item;
165
166 fn empty() -> Self;
167
168 fn count(&self) -> usize;
169
170 fn limit(&self) -> usize;
171
172 fn append(&mut self, item: Self::Item);
173}
174
175#[diagnostic::do_not_recommend]
176impl<T, const N: usize> Collection for Values<T, N> {
177 type Item = T;
178
179 fn empty() -> Self {
180 Self::new()
181 }
182
183 fn count(&self) -> usize {
184 self.len
185 }
186
187 fn limit(&self) -> usize {
188 N
189 }
190
191 fn append(&mut self, item: T) {
192 let _ = self.push(item);
193 }
194}
195
196#[cfg(feature = "heapless")]
197#[diagnostic::do_not_recommend]
198impl<T, const N: usize, L: heapless::LenType> Collection for heapless::Vec<T, N, L> {
199 type Item = T;
200
201 fn empty() -> Self {
202 Self::new()
203 }
204
205 fn count(&self) -> usize {
206 self.len()
207 }
208
209 fn limit(&self) -> usize {
210 self.capacity()
211 }
212
213 fn append(&mut self, item: T) {
214 let _ = self.push(item);
215 }
216}
217
218#[cfg(feature = "alloc")]
219#[diagnostic::do_not_recommend]
220impl<T> Collection for alloc::vec::Vec<T> {
221 type Item = T;
222
223 fn empty() -> Self {
224 Self::new()
225 }
226
227 fn count(&self) -> usize {
228 self.len()
229 }
230
231 fn limit(&self) -> usize {
232 usize::MAX
233 }
234
235 fn append(&mut self, item: T) {
236 self.push(item);
237 }
238}
239
240fn append<'a, V: Input<'a>, C: Collection>(
241 collection: &mut C,
242 value: V,
243 name: &'static str,
244 max: usize,
245 convert: &mut impl FnMut(V) -> Result<C::Item, Error<'a>>,
246) -> Result<(), Error<'a>> {
247 if collection.count() >= max {
248 return Err(Error::TooManyValues {
249 name,
250 value: text(value, name)?,
251 max,
252 });
253 }
254 let item = convert(value)?;
255 collection.append(item);
256 Ok(())
257}
258
259#[doc(hidden)]
260pub fn push_values<'a, V: Input<'a>, C: Collection>(
261 slot: &mut Option<C>,
262 value: V,
263 delimiter: Option<char>,
264 name: &'static str,
265 max: usize,
266 mut convert: impl FnMut(V) -> Result<C::Item, Error<'a>>,
267) -> Result<(), Error<'a>> {
268 let collection = slot.get_or_insert_with(C::empty);
269 let max = max.min(collection.limit());
270 let Some(delimiter) = delimiter else {
271 return append(collection, value, name, max, &mut convert);
272 };
273 let mut rest = value;
274 while let Some((piece, tail)) = rest.split_once(delimiter) {
275 append(collection, piece, name, max, &mut convert)?;
276 rest = tail;
277 }
278 append(collection, rest, name, max, &mut convert)
279}
280
281#[doc(hidden)]
282pub fn values_len<C: Collection>(slot: &Option<C>) -> usize {
283 slot.as_ref().map_or(0, C::count)
284}
285
286#[doc(hidden)]
287pub fn finish_values<'a, C: Collection>(
288 slot: Option<C>,
289 name: &'static str,
290 min: usize,
291) -> Result<C, Error<'a>> {
292 let collection = slot.unwrap_or_else(C::empty);
293 let actual = collection.count();
294 if actual >= min {
295 Ok(collection)
296 } else if actual == 0 {
297 Err(Error::MissingArgument(name))
298 } else {
299 Err(Error::TooFewValues { name, min, actual })
300 }
301}