1use super::{BoundedSlice, BoundedVec};
22use crate::Get;
23use alloc::vec::Vec;
24use core::{
25 marker::PhantomData,
26 ops::{Deref, Index, IndexMut},
27 slice::SliceIndex,
28};
29#[cfg(feature = "serde")]
30use serde::{
31 de::{Error, SeqAccess, Visitor},
32 Deserialize, Deserializer, Serialize,
33};
34
35#[cfg_attr(feature = "serde", derive(Serialize), serde(transparent))]
43#[cfg_attr(feature = "scale-codec", derive(scale_codec::Encode, scale_info::TypeInfo))]
44#[cfg_attr(feature = "scale-codec", scale_info(skip_type_params(S)))]
45#[cfg_attr(feature = "jam-codec", derive(jam_codec::Encode))]
46pub struct WeakBoundedVec<T, S>(
47 pub(super) Vec<T>,
48 #[cfg_attr(feature = "serde", serde(skip_serializing))] PhantomData<S>,
49);
50
51#[cfg(feature = "serde")]
52impl<'de, T, S: Get<u32>> Deserialize<'de> for WeakBoundedVec<T, S>
53where
54 T: Deserialize<'de>,
55{
56 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
57 where
58 D: Deserializer<'de>,
59 {
60 struct VecVisitor<T, S: Get<u32>>(PhantomData<(T, S)>);
61
62 impl<'de, T, S: Get<u32>> Visitor<'de> for VecVisitor<T, S>
63 where
64 T: Deserialize<'de>,
65 {
66 type Value = Vec<T>;
67
68 fn expecting(&self, formatter: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
69 formatter.write_str("a sequence")
70 }
71
72 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
73 where
74 A: SeqAccess<'de>,
75 {
76 let size = seq.size_hint().unwrap_or(0);
77 let max = match usize::try_from(S::get()) {
78 Ok(n) => n,
79 Err(_) => return Err(A::Error::custom("can't convert to usize")),
80 };
81 if size > max {
82 log::warn!(
83 target: "runtime",
84 "length of a bounded vector while deserializing is not respected.",
85 );
86 }
87 let mut values = Vec::with_capacity(size);
88
89 while let Some(value) = seq.next_element()? {
90 values.push(value);
91 if values.len() > max {
92 log::warn!(
93 target: "runtime",
94 "length of a bounded vector while deserializing is not respected.",
95 );
96 }
97 }
98
99 Ok(values)
100 }
101 }
102
103 let visitor: VecVisitor<T, S> = VecVisitor(PhantomData);
104 deserializer
105 .deserialize_seq(visitor)
106 .map(|v| WeakBoundedVec::<T, S>::try_from(v).map_err(|_| Error::custom("out of bounds")))?
107 }
108}
109
110impl<T, S> WeakBoundedVec<T, S> {
111 fn unchecked_from(t: Vec<T>) -> Self {
113 Self(t, Default::default())
114 }
115
116 pub fn into_inner(self) -> Vec<T> {
123 self.0
124 }
125
126 pub fn remove(&mut self, index: usize) -> T {
132 self.0.remove(index)
133 }
134
135 pub fn swap_remove(&mut self, index: usize) -> T {
141 self.0.swap_remove(index)
142 }
143
144 pub fn retain<F: FnMut(&T) -> bool>(&mut self, f: F) {
146 self.0.retain(f)
147 }
148
149 pub fn get_mut<I: SliceIndex<[T]>>(&mut self, index: I) -> Option<&mut <I as SliceIndex<[T]>>::Output> {
151 self.0.get_mut(index)
152 }
153}
154
155impl<T, S: Get<u32>> WeakBoundedVec<T, S> {
156 pub fn bound() -> usize {
158 S::get() as usize
159 }
160
161 pub fn force_from(t: Vec<T>, scope: Option<&'static str>) -> Self {
165 if t.len() > Self::bound() {
166 log::warn!(
167 target: "runtime",
168 "length of a bounded vector in scope {} is not respected.",
169 scope.unwrap_or("UNKNOWN"),
170 );
171 }
172
173 Self::unchecked_from(t)
174 }
175
176 pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut Vec<T>)) -> Option<Self> {
184 mutate(&mut self.0);
185 (self.0.len() <= Self::bound()).then(move || self)
186 }
187
188 pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), ()> {
195 if self.len() < Self::bound() {
196 self.0.insert(index, element);
197 Ok(())
198 } else {
199 Err(())
200 }
201 }
202
203 pub fn try_push(&mut self, element: T) -> Result<(), ()> {
210 if self.len() < Self::bound() {
211 self.0.push(element);
212 Ok(())
213 } else {
214 Err(())
215 }
216 }
217
218 pub fn is_full(&self) -> bool {
220 self.len() >= Self::bound()
221 }
222}
223
224impl<T, S> Default for WeakBoundedVec<T, S> {
225 fn default() -> Self {
226 Self::unchecked_from(Vec::default())
228 }
229}
230
231impl<T, S> core::fmt::Debug for WeakBoundedVec<T, S>
232where
233 Vec<T>: core::fmt::Debug,
234 S: Get<u32>,
235{
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 f.debug_tuple("WeakBoundedVec").field(&self.0).field(&Self::bound()).finish()
238 }
239}
240
241impl<T, S> Clone for WeakBoundedVec<T, S>
242where
243 T: Clone,
244{
245 fn clone(&self) -> Self {
246 Self::unchecked_from(self.0.clone())
248 }
249}
250
251impl<T, S: Get<u32>> TryFrom<Vec<T>> for WeakBoundedVec<T, S> {
252 type Error = ();
253 fn try_from(t: Vec<T>) -> Result<Self, Self::Error> {
254 if t.len() <= Self::bound() {
255 Ok(Self::unchecked_from(t))
257 } else {
258 Err(())
259 }
260 }
261}
262
263impl<T, S> AsRef<Vec<T>> for WeakBoundedVec<T, S> {
265 fn as_ref(&self) -> &Vec<T> {
266 &self.0
267 }
268}
269
270impl<T, S> AsRef<[T]> for WeakBoundedVec<T, S> {
271 fn as_ref(&self) -> &[T] {
272 &self.0
273 }
274}
275
276impl<T, S> AsMut<[T]> for WeakBoundedVec<T, S> {
277 fn as_mut(&mut self) -> &mut [T] {
278 &mut self.0
279 }
280}
281
282impl<T, S> Deref for WeakBoundedVec<T, S> {
284 type Target = Vec<T>;
285
286 fn deref(&self) -> &Self::Target {
287 &self.0
288 }
289}
290
291impl<T, S, I> Index<I> for WeakBoundedVec<T, S>
293where
294 I: SliceIndex<[T]>,
295{
296 type Output = I::Output;
297
298 #[inline]
299 fn index(&self, index: I) -> &Self::Output {
300 self.0.index(index)
301 }
302}
303
304impl<T, S, I> IndexMut<I> for WeakBoundedVec<T, S>
305where
306 I: SliceIndex<[T]>,
307{
308 #[inline]
309 fn index_mut(&mut self, index: I) -> &mut Self::Output {
310 self.0.index_mut(index)
311 }
312}
313
314impl<T, S> core::iter::IntoIterator for WeakBoundedVec<T, S> {
315 type Item = T;
316 type IntoIter = alloc::vec::IntoIter<T>;
317 fn into_iter(self) -> Self::IntoIter {
318 self.0.into_iter()
319 }
320}
321
322impl<'a, T, S> core::iter::IntoIterator for &'a WeakBoundedVec<T, S> {
323 type Item = &'a T;
324 type IntoIter = core::slice::Iter<'a, T>;
325 fn into_iter(self) -> Self::IntoIter {
326 self.0.iter()
327 }
328}
329
330impl<'a, T, S> core::iter::IntoIterator for &'a mut WeakBoundedVec<T, S> {
331 type Item = &'a mut T;
332 type IntoIter = core::slice::IterMut<'a, T>;
333 fn into_iter(self) -> Self::IntoIter {
334 self.0.iter_mut()
335 }
336}
337
338impl<T, BoundSelf, BoundRhs> PartialEq<WeakBoundedVec<T, BoundRhs>> for WeakBoundedVec<T, BoundSelf>
339where
340 T: PartialEq,
341 BoundSelf: Get<u32>,
342 BoundRhs: Get<u32>,
343{
344 fn eq(&self, rhs: &WeakBoundedVec<T, BoundRhs>) -> bool {
345 self.0 == rhs.0
346 }
347}
348
349impl<T, BoundSelf, BoundRhs> PartialEq<BoundedVec<T, BoundRhs>> for WeakBoundedVec<T, BoundSelf>
350where
351 T: PartialEq,
352 BoundSelf: Get<u32>,
353 BoundRhs: Get<u32>,
354{
355 fn eq(&self, rhs: &BoundedVec<T, BoundRhs>) -> bool {
356 self.0 == rhs.0
357 }
358}
359
360impl<'a, T, BoundSelf, BoundRhs> PartialEq<BoundedSlice<'a, T, BoundRhs>> for WeakBoundedVec<T, BoundSelf>
361where
362 T: PartialEq,
363 BoundSelf: Get<u32>,
364 BoundRhs: Get<u32>,
365{
366 fn eq(&self, rhs: &BoundedSlice<'a, T, BoundRhs>) -> bool {
367 self.0 == rhs.0
368 }
369}
370
371impl<T: PartialEq, S: Get<u32>> PartialEq<Vec<T>> for WeakBoundedVec<T, S> {
372 fn eq(&self, other: &Vec<T>) -> bool {
373 &self.0 == other
374 }
375}
376
377impl<T, S: Get<u32>> Eq for WeakBoundedVec<T, S> where T: Eq {}
378
379impl<T, BoundSelf, BoundRhs> PartialOrd<WeakBoundedVec<T, BoundRhs>> for WeakBoundedVec<T, BoundSelf>
380where
381 T: PartialOrd,
382 BoundSelf: Get<u32>,
383 BoundRhs: Get<u32>,
384{
385 fn partial_cmp(&self, other: &WeakBoundedVec<T, BoundRhs>) -> Option<core::cmp::Ordering> {
386 self.0.partial_cmp(&other.0)
387 }
388}
389
390impl<T, BoundSelf, BoundRhs> PartialOrd<BoundedVec<T, BoundRhs>> for WeakBoundedVec<T, BoundSelf>
391where
392 T: PartialOrd,
393 BoundSelf: Get<u32>,
394 BoundRhs: Get<u32>,
395{
396 fn partial_cmp(&self, other: &BoundedVec<T, BoundRhs>) -> Option<core::cmp::Ordering> {
397 self.0.partial_cmp(&other.0)
398 }
399}
400
401impl<'a, T, BoundSelf, BoundRhs> PartialOrd<BoundedSlice<'a, T, BoundRhs>> for WeakBoundedVec<T, BoundSelf>
402where
403 T: PartialOrd,
404 BoundSelf: Get<u32>,
405 BoundRhs: Get<u32>,
406{
407 fn partial_cmp(&self, other: &BoundedSlice<'a, T, BoundRhs>) -> Option<core::cmp::Ordering> {
408 (&*self.0).partial_cmp(other.0)
409 }
410}
411
412impl<T: Ord, S: Get<u32>> Ord for WeakBoundedVec<T, S> {
413 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
414 self.0.cmp(&other.0)
415 }
416}
417
418#[cfg(any(feature = "scale-codec", feature = "jam-codec"))]
419macro_rules! codec_impl {
420 ($codec:ident) => {
421 use super::*;
422 use $codec::{Compact, Decode, DecodeLength, DecodeWithMemTracking, Encode, Error, Input, MaxEncodedLen};
423
424 impl<T, S> MaxEncodedLen for WeakBoundedVec<T, S>
425 where
426 T: MaxEncodedLen,
427 S: Get<u32>,
428 WeakBoundedVec<T, S>: Encode,
429 {
430 fn max_encoded_len() -> usize {
431 Compact(S::get())
435 .encoded_size()
436 .saturating_add(Self::bound().saturating_mul(T::max_encoded_len()))
437 }
438 }
439
440 impl<T: Decode, S: Get<u32>> Decode for WeakBoundedVec<T, S> {
441 fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
442 let inner = Vec::<T>::decode(input)?;
443 Ok(Self::force_from(inner, Some("decode")))
444 }
445
446 fn skip<I: Input>(input: &mut I) -> Result<(), Error> {
447 Vec::<T>::skip(input)
448 }
449 }
450
451 impl<T: DecodeWithMemTracking, S: Get<u32>> DecodeWithMemTracking for WeakBoundedVec<T, S> {}
452
453 impl<T, S> DecodeLength for WeakBoundedVec<T, S> {
454 fn len(self_encoded: &[u8]) -> Result<usize, Error> {
455 <Vec<T> as DecodeLength>::len(self_encoded)
458 }
459 }
460 };
461}
462
463#[cfg(feature = "scale-codec")]
464mod scale_impl {
465 codec_impl!(scale_codec);
466}
467
468#[cfg(feature = "jam-codec")]
469mod jam_impl {
470 codec_impl!(jam_codec);
471}
472
473#[cfg(test)]
474mod test {
475 use super::*;
476 use crate::ConstU32;
477 use alloc::vec;
478 #[cfg(feature = "scale-codec")]
479 use scale_codec::{Decode, Encode};
480
481 #[test]
482 fn bound_returns_correct_value() {
483 assert_eq!(WeakBoundedVec::<u32, ConstU32<7>>::bound(), 7);
484 }
485
486 #[test]
487 fn try_insert_works() {
488 let mut bounded: WeakBoundedVec<u32, ConstU32<4>> = vec![1, 2, 3].try_into().unwrap();
489 bounded.try_insert(1, 0).unwrap();
490 assert_eq!(*bounded, vec![1, 0, 2, 3]);
491
492 assert!(bounded.try_insert(0, 9).is_err());
493 assert_eq!(*bounded, vec![1, 0, 2, 3]);
494 }
495
496 #[test]
497 #[should_panic(expected = "insertion index (is 9) should be <= len (is 3)")]
498 fn try_inert_panics_if_oob() {
499 let mut bounded: WeakBoundedVec<u32, ConstU32<4>> = vec![1, 2, 3].try_into().unwrap();
500 bounded.try_insert(9, 0).unwrap();
501 }
502
503 #[test]
504 fn try_push_works() {
505 let mut bounded: WeakBoundedVec<u32, ConstU32<4>> = vec![1, 2, 3].try_into().unwrap();
506 bounded.try_push(0).unwrap();
507 assert_eq!(*bounded, vec![1, 2, 3, 0]);
508
509 assert!(bounded.try_push(9).is_err());
510 }
511
512 #[test]
513 fn deref_coercion_works() {
514 let bounded: WeakBoundedVec<u32, ConstU32<7>> = vec![1, 2, 3].try_into().unwrap();
515 assert_eq!(bounded.len(), 3);
517 assert!(bounded.iter().next().is_some());
518 assert!(!bounded.is_empty());
519 }
520
521 #[test]
522 fn try_mutate_works() {
523 let bounded: WeakBoundedVec<u32, ConstU32<7>> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap();
524 let bounded = bounded.try_mutate(|v| v.push(7)).unwrap();
525 assert_eq!(bounded.len(), 7);
526 assert!(bounded.try_mutate(|v| v.push(8)).is_none());
527 }
528
529 #[test]
530 fn slice_indexing_works() {
531 let bounded: WeakBoundedVec<u32, ConstU32<7>> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap();
532 assert_eq!(&bounded[0..=2], &[1, 2, 3]);
533 }
534
535 #[test]
536 fn vec_eq_works() {
537 let bounded: WeakBoundedVec<u32, ConstU32<7>> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap();
538 assert_eq!(bounded, vec![1, 2, 3, 4, 5, 6]);
539 }
540
541 #[test]
542 #[cfg(feature = "scale-codec")]
543 fn too_big_succeed_to_decode() {
544 let v: Vec<u32> = vec![1, 2, 3, 4, 5];
545 let w = WeakBoundedVec::<u32, ConstU32<4>>::decode(&mut &v.encode()[..]).unwrap();
546 assert_eq!(v, *w);
547 }
548
549 #[test]
550 fn is_full_works() {
551 let mut bounded: WeakBoundedVec<u32, ConstU32<4>> = vec![1, 2, 3].try_into().unwrap();
552 assert!(!bounded.is_full());
553 bounded.try_insert(1, 0).unwrap();
554 assert_eq!(*bounded, vec![1, 0, 2, 3]);
555
556 assert!(bounded.is_full());
557 assert!(bounded.try_insert(0, 9).is_err());
558 assert_eq!(*bounded, vec![1, 0, 2, 3]);
559 }
560}