1#![allow(unused_imports)]
2#![allow(dead_code)]
3
4use crate::cfg::*;
5pub use crate::error::*;
6
7use core::fmt;
8use core::marker::PhantomData;
9use core::ops::Deref;
10
11#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
63#[allow(private_bounds)]
64pub struct VecM<T, const MAX: u32 = { u32::MAX }>(pub Vec<T>)
65where
66 T: StaticIfNoAlloc;
67
68#[cfg(feature = "alloc")]
74pub trait StaticIfNoAlloc {}
75#[cfg(feature = "alloc")]
76impl<T> StaticIfNoAlloc for T {}
77
78#[cfg(not(feature = "alloc"))]
84pub trait StaticIfNoAlloc: 'static {}
85#[cfg(not(feature = "alloc"))]
86impl<T: 'static> StaticIfNoAlloc for T {}
87
88#[cfg(all(feature = "serde", feature = "alloc"))]
89#[cfg_attr(docsrs, doc(cfg(all(feature = "serde", feature = "alloc"))))]
90impl<T, const MAX: u32> Serialize for VecM<T, MAX>
91where
92 T: Serialize,
93{
94 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
95 where
96 S: Serializer,
97 {
98 if self.0.len() > Self::MAX_LEN {
99 return Err(<S::Error as SerError>::custom(Error::LengthExceedsMax));
100 }
101 self.0.serialize(ser)
102 }
103}
104
105#[cfg(all(feature = "serde", feature = "alloc"))]
106#[cfg_attr(docsrs, doc(cfg(all(feature = "serde", feature = "alloc"))))]
107impl<'de, T, const MAX: u32> Deserialize<'de> for VecM<T, MAX>
108where
109 T: Deserialize<'de>,
110{
111 fn deserialize<D>(de: D) -> Result<Self, D::Error>
112 where
113 D: Deserializer<'de>,
114 {
115 struct VecMVisitor<T, const MAX: u32>(PhantomData<T>);
116
117 impl<'de, T, const MAX: u32> Visitor<'de> for VecMVisitor<T, MAX>
118 where
119 T: Deserialize<'de>,
120 {
121 type Value = VecM<T, MAX>;
122
123 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
124 write!(f, "a sequence with length at most {}", MAX)
125 }
126
127 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
128 where
129 A: SeqAccess<'de>,
130 {
131 let mut buf = Vec::new();
132 if let Some(len) = seq.size_hint() {
133 if len > VecM::<T, MAX>::MAX_LEN {
134 return Err(<A::Error as DeError>::invalid_length(len, &self));
135 }
136 let cap = len.min(crate::MAX_PREALLOC_BYTES / core::mem::size_of::<T>().max(1));
137 buf.reserve(cap);
138 }
139
140 while buf.len() < VecM::<T, MAX>::MAX_LEN {
141 match seq.next_element::<T>()? {
142 Some(value) => buf.push(value),
143 None => return Ok(VecM(buf)),
144 }
145 }
146 if seq.next_element::<IgnoredAny>()?.is_some() {
147 return Err(match buf.len().checked_add(1) {
148 Some(overlimit) => <A::Error as DeError>::invalid_length(overlimit, &self),
149 None => DeError::custom(format_args!(
150 "sequence length exceeds maximum of {MAX}"
151 )),
152 });
153 }
154 Ok(VecM(buf))
155 }
156 }
157
158 de.deserialize_seq(VecMVisitor::<T, MAX>(PhantomData))
159 }
160}
161
162#[cfg(feature = "schemars")]
163#[cfg_attr(docsrs, doc(cfg(feature = "schemars")))]
164impl<T: schemars::JsonSchema, const MAX: u32> schemars::JsonSchema for VecM<T, MAX> {
165 fn schema_name() -> alloc::borrow::Cow<'static, str> {
166 alloc::format!("VecM<{}, {}>", T::schema_name(), MAX).into()
167 }
168
169 fn schema_id() -> alloc::borrow::Cow<'static, str> {
170 alloc::format!("xdr_common::VecM<{}, {}>", T::schema_id(), MAX).into()
171 }
172
173 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
174 let items = generator.subschema_for::<T>();
175 schemars::json_schema!({
176 "type": "array",
177 "items": items,
178 "maxItems": MAX,
179 })
180 }
181}
182
183impl<T: StaticIfNoAlloc, const MAX: u32> Deref for VecM<T, MAX> {
184 type Target = Vec<T>;
185
186 fn deref(&self) -> &Self::Target {
187 &self.0
188 }
189}
190
191impl<T: StaticIfNoAlloc, const MAX: u32> Default for VecM<T, MAX> {
192 fn default() -> Self {
193 Self(Vec::default())
194 }
195}
196
197#[allow(private_bounds)]
198impl<T: StaticIfNoAlloc, const MAX: u32> VecM<T, MAX> {
199 pub const MAX_LEN: usize = { MAX as usize };
201
202 #[must_use]
204 #[allow(clippy::unused_self)]
205 pub fn max_len(&self) -> usize {
206 Self::MAX_LEN
207 }
208
209 #[must_use]
211 pub fn as_vec(&self) -> &Vec<T> {
212 self.as_ref()
213 }
214
215 #[must_use]
219 pub const fn as_slice(&self) -> &[T] {
220 #[cfg(feature = "alloc")]
221 let s: &[T] = self.0.as_slice();
222 #[cfg(not(feature = "alloc"))]
223 let s: &[T] = self.0;
224 s
225 }
226}
227
228#[allow(private_bounds)]
229impl<T: Clone + StaticIfNoAlloc, const MAX: u32> VecM<T, MAX> {
230 #[must_use]
234 #[cfg(feature = "alloc")]
235 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
236 pub fn to_vec(&self) -> Vec<T> {
237 self.into()
238 }
239
240 #[must_use]
242 pub fn into_vec(self) -> Vec<T> {
243 self.into()
244 }
245}
246
247#[allow(private_bounds)]
248impl<T: Clone + StaticIfNoAlloc> VecM<T, 1> {
249 #[must_use]
254 pub fn to_option(&self) -> Option<T> {
255 self.0.first().cloned()
256 }
257}
258
259#[cfg(not(feature = "alloc"))]
260#[cfg_attr(docsrs, doc(cfg(not(feature = "alloc"))))]
261impl<T: Clone + 'static> From<VecM<T, 1>> for Option<T> {
262 fn from(v: VecM<T, 1>) -> Self {
263 v.to_option()
264 }
265}
266
267#[cfg(feature = "alloc")]
268impl<T> VecM<T, 1> {
269 #[must_use]
276 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
277 pub fn into_option(mut self) -> Option<T> {
278 self.0.drain(..).next()
279 }
280}
281
282#[cfg(feature = "alloc")]
283#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
284impl<T> From<VecM<T, 1>> for Option<T> {
285 fn from(v: VecM<T, 1>) -> Self {
286 v.into_option()
287 }
288}
289
290impl<T: StaticIfNoAlloc, const MAX: u32> TryFrom<Vec<T>> for VecM<T, MAX> {
291 type Error = Error;
292
293 fn try_from(v: Vec<T>) -> Result<Self, Error> {
294 let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?;
295 if len <= MAX {
296 Ok(VecM(v))
297 } else {
298 Err(Error::LengthExceedsMax)
299 }
300 }
301}
302
303impl<T: StaticIfNoAlloc, const MAX: u32> From<VecM<T, MAX>> for Vec<T> {
304 fn from(v: VecM<T, MAX>) -> Self {
305 v.0
306 }
307}
308
309#[cfg(feature = "alloc")]
310#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
311impl<T: Clone, const MAX: u32> From<&VecM<T, MAX>> for Vec<T> {
312 fn from(v: &VecM<T, MAX>) -> Self {
313 v.0.clone()
314 }
315}
316
317impl<T: StaticIfNoAlloc, const MAX: u32> AsRef<Vec<T>> for VecM<T, MAX> {
318 fn as_ref(&self) -> &Vec<T> {
319 &self.0
320 }
321}
322
323#[cfg(feature = "alloc")]
324#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
325impl<T: Clone, const MAX: u32> TryFrom<&Vec<T>> for VecM<T, MAX> {
326 type Error = Error;
327
328 fn try_from(v: &Vec<T>) -> Result<Self, Error> {
329 v.as_slice().try_into()
330 }
331}
332
333#[cfg(feature = "alloc")]
334#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
335impl<T: Clone, const MAX: u32> TryFrom<&[T]> for VecM<T, MAX> {
336 type Error = Error;
337
338 fn try_from(v: &[T]) -> Result<Self, Error> {
339 let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?;
340 if len <= MAX {
341 Ok(VecM(v.to_vec()))
342 } else {
343 Err(Error::LengthExceedsMax)
344 }
345 }
346}
347
348impl<T: StaticIfNoAlloc, const MAX: u32> AsRef<[T]> for VecM<T, MAX> {
349 #[cfg(feature = "alloc")]
350 fn as_ref(&self) -> &[T] {
351 self.0.as_ref()
352 }
353 #[cfg(not(feature = "alloc"))]
354 fn as_ref(&self) -> &[T] {
355 self.0
356 }
357}
358
359#[cfg(feature = "alloc")]
360#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
361impl<T: Clone, const N: usize, const MAX: u32> TryFrom<[T; N]> for VecM<T, MAX> {
362 type Error = Error;
363
364 fn try_from(v: [T; N]) -> Result<Self, Error> {
365 let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?;
366 if len <= MAX {
367 Ok(VecM(v.to_vec()))
368 } else {
369 Err(Error::LengthExceedsMax)
370 }
371 }
372}
373
374#[cfg(feature = "alloc")]
375#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
376impl<T: Clone, const N: usize, const MAX: u32> TryFrom<VecM<T, MAX>> for [T; N] {
377 type Error = VecM<T, MAX>;
378
379 fn try_from(v: VecM<T, MAX>) -> core::result::Result<Self, Self::Error> {
380 let s: [T; N] = v.0.try_into().map_err(|v: Vec<T>| VecM::<T, MAX>(v))?;
381 Ok(s)
382 }
383}
384
385#[cfg(feature = "alloc")]
386#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
387impl<T: Clone, const N: usize, const MAX: u32> TryFrom<&[T; N]> for VecM<T, MAX> {
388 type Error = Error;
389
390 fn try_from(v: &[T; N]) -> Result<Self, Error> {
391 let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?;
392 if len <= MAX {
393 Ok(VecM(v.to_vec()))
394 } else {
395 Err(Error::LengthExceedsMax)
396 }
397 }
398}
399
400#[cfg(not(feature = "alloc"))]
401#[cfg_attr(docsrs, doc(cfg(not(feature = "alloc"))))]
402impl<T: Clone, const N: usize, const MAX: u32> TryFrom<&'static [T; N]> for VecM<T, MAX> {
403 type Error = Error;
404
405 fn try_from(v: &'static [T; N]) -> Result<Self, Error> {
406 let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?;
407 if len <= MAX {
408 Ok(VecM(v))
409 } else {
410 Err(Error::LengthExceedsMax)
411 }
412 }
413}
414
415#[cfg(feature = "alloc")]
416#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
417impl<const MAX: u32> TryFrom<&String> for VecM<u8, MAX> {
418 type Error = Error;
419
420 fn try_from(v: &String) -> Result<Self, Error> {
421 let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?;
422 if len <= MAX {
423 Ok(VecM(v.as_bytes().to_vec()))
424 } else {
425 Err(Error::LengthExceedsMax)
426 }
427 }
428}
429
430#[cfg(feature = "alloc")]
431#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
432impl<const MAX: u32> TryFrom<String> for VecM<u8, MAX> {
433 type Error = Error;
434
435 fn try_from(v: String) -> Result<Self, Error> {
436 let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?;
437 if len <= MAX {
438 Ok(VecM(v.into()))
439 } else {
440 Err(Error::LengthExceedsMax)
441 }
442 }
443}
444
445#[cfg(feature = "alloc")]
446#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
447impl<const MAX: u32> TryFrom<&str> for VecM<u8, MAX> {
448 type Error = Error;
449
450 fn try_from(v: &str) -> Result<Self, Error> {
451 let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?;
452 if len <= MAX {
453 Ok(VecM(v.into()))
454 } else {
455 Err(Error::LengthExceedsMax)
456 }
457 }
458}
459
460#[cfg(not(feature = "alloc"))]
461#[cfg_attr(docsrs, doc(cfg(not(feature = "alloc"))))]
462impl<const MAX: u32> TryFrom<&'static str> for VecM<u8, MAX> {
463 type Error = Error;
464
465 fn try_from(v: &'static str) -> Result<Self, Error> {
466 let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?;
467 if len <= MAX {
468 Ok(VecM(v.as_bytes()))
469 } else {
470 Err(Error::LengthExceedsMax)
471 }
472 }
473}
474
475#[cfg(test)]
476mod tests {
477 use super::*;
478
479 #[cfg(feature = "alloc")]
480 extern crate alloc;
481 #[cfg(feature = "alloc")]
482 use alloc::vec;
483
484 #[test]
485 #[cfg(feature = "alloc")]
486 fn test_as_slice_const() {
487 const fn as_slice_in_const<const M: u32>(v: &VecM<u32, M>) -> &[u32] {
491 v.as_slice()
492 }
493 let v: VecM<u32, 3> = vec![1, 2].try_into().unwrap();
494 assert_eq!(as_slice_in_const(&v), &[1, 2]);
495 }
496
497 #[test]
498 #[cfg(not(feature = "alloc"))]
499 fn test_as_slice_const() {
500 const V: VecM<u32, 3> = VecM(&[1, 2]);
501 const SLICE: &[u32] = V.as_slice();
502 assert_eq!(SLICE, &[1, 2]);
503 }
504
505 #[test]
506 #[cfg(feature = "alloc")]
507 fn test_vecm_alloc_basic() {
508 let v: VecM<u32, 10> = vec![1, 2, 3].try_into().unwrap();
510 assert_eq!(v.len(), 3);
511 assert_eq!(v.max_len(), 10);
512 assert_eq!(v[0], 1);
513
514 let too_long: Result<VecM<u32, 5>, _> = vec![1, 2, 3, 4, 5, 6].try_into();
516 assert!(too_long.is_err());
517 }
518
519 #[test]
520 #[cfg(all(feature = "serde", feature = "alloc"))]
521 fn test_vecm_serde_deser_rejects_overlimit() {
522 let ok: VecM<u32, 3> = serde_json::from_str("[1,2,3]").unwrap();
523 assert_eq!(ok.as_vec(), &vec![1, 2, 3]);
524
525 let under: VecM<u32, 5> = serde_json::from_str("[1]").unwrap();
526 assert_eq!(under.as_vec(), &vec![1]);
527
528 let empty: VecM<u32, 0> = serde_json::from_str("[]").unwrap();
529 assert!(empty.is_empty());
530
531 let err = serde_json::from_str::<VecM<u32, 2>>("[1,2,3]").unwrap_err();
532 let msg = alloc::format!("{err}");
533 assert!(msg.contains("length at most 2"), "{msg}");
534
535 let err = serde_json::from_str::<VecM<u32, 0>>("[1]").unwrap_err();
536 let msg = alloc::format!("{err}");
537 assert!(msg.contains("length at most 0"), "{msg}");
538 }
539
540 #[test]
541 #[cfg(all(feature = "serde", feature = "alloc"))]
542 fn test_vecm_serde_serialize_rejects_overlimit() {
543 let value = VecM::<u32, 1>(vec![1, 2]);
544 let err = serde_json::to_value(&value).unwrap_err();
545 let msg = alloc::format!("{err}");
546 assert!(msg.contains("max length exceeded"), "{msg}");
547 }
548
549 #[test]
550 #[cfg(all(feature = "serde", feature = "alloc"))]
551 fn test_vecm_serde_serialize_accepts_at_max() {
552 let value = VecM::<u32, 2>(vec![1, 2]);
553 let json = serde_json::to_value(&value).unwrap();
554 assert_eq!(json, serde_json::json!([1, 2]));
555 }
556
557 #[test]
558 #[cfg(not(feature = "alloc"))]
559 fn test_vecm_noalloc_basic() {
560 static DATA: [u32; 3] = [1, 2, 3];
562 let v: VecM<u32, 10> = (&DATA).try_into().unwrap();
563 assert_eq!(v.len(), 3);
564 assert_eq!(v.max_len(), 10);
565 assert_eq!(v[0], 1);
566
567 static LONG_DATA: [u32; 6] = [1, 2, 3, 4, 5, 6];
569 let too_long: Result<VecM<u32, 5>, _> = (&LONG_DATA).try_into();
570 assert!(too_long.is_err());
571 }
572}