gear_core/limited/
vec.rs

1// This file is part of Gear.
2
3// Copyright (C) 2021-2025 Gear Technologies Inc.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! This module provides type for vector with statically limited length.
20
21use core::fmt::{self, Formatter};
22
23use alloc::{vec, vec::Vec};
24
25use derive_more::{AsMut, AsRef, Debug, Deref, DerefMut, Display, Error, Into, IntoIterator};
26use gprimitives::utils::ByteSliceFormatter;
27use scale_decode::DecodeAsType;
28use scale_encode::EncodeAsType;
29use scale_info::{
30    TypeInfo,
31    scale::{Decode, Encode},
32};
33
34/// Vector with limited length.
35#[derive(
36    Clone,
37    Default,
38    PartialEq,
39    Eq,
40    PartialOrd,
41    Ord,
42    Decode,
43    DecodeAsType,
44    Encode,
45    EncodeAsType,
46    Hash,
47    TypeInfo,
48    AsRef,
49    AsMut,
50    Deref,
51    DerefMut,
52    IntoIterator,
53    Into,
54)]
55#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
56#[as_ref(forward)]
57#[as_mut(forward)]
58#[deref(forward)]
59#[deref_mut(forward)]
60#[into_iterator(owned, ref, ref_mut)]
61pub struct LimitedVec<T, const N: usize>(Vec<T>);
62
63impl<T: Clone, const N: usize> TryFrom<&[T]> for LimitedVec<T, N> {
64    type Error = LimitedVecError;
65
66    fn try_from(slice: &[T]) -> Result<Self, Self::Error> {
67        Self::validate_len(slice.len()).map(|_| Self(slice.to_vec()))
68    }
69}
70
71impl<T, const N: usize> TryFrom<Vec<T>> for LimitedVec<T, N> {
72    type Error = LimitedVecError;
73    fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> {
74        Self::validate_len(vec.len()).map(|_| Self(vec))
75    }
76}
77
78impl<T, const N: usize> LimitedVec<T, N> {
79    /// Maximum length of the vector.
80    pub const MAX_LEN: usize = N;
81
82    /// Validates given length.
83    ///
84    /// Returns `Ok(())` if the vector can store such number
85    /// of elements and `Err(LimitedVecError)` otherwise.
86    const fn validate_len(len: usize) -> Result<(), LimitedVecError> {
87        if len <= N {
88            Ok(())
89        } else {
90            Err(LimitedVecError)
91        }
92    }
93
94    /// Constructs a new, empty `LimitedVec<T>`.
95    pub const fn new() -> Self {
96        Self(vec![])
97    }
98
99    /// Creates a new limited vector with elements
100    /// initialized with [`Default::default`].
101    pub fn repeat(value: T) -> Self
102    where
103        T: Clone,
104    {
105        Self(vec![value; N])
106    }
107
108    /// Creates a new limited vector with given
109    /// length by repeatedly cloning a value.
110    pub fn try_repeat(value: T, len: usize) -> Result<Self, LimitedVecError>
111    where
112        T: Clone,
113    {
114        Self::validate_len(len).map(|_| Self(vec![value; len]))
115    }
116
117    /// Extends the vector to its limit by
118    /// repeatedly adding a value.
119    pub fn extend_with(&mut self, value: T)
120    where
121        T: Clone,
122    {
123        self.0.resize(N, value)
124    }
125
126    /// Appends a value to the end of the vector.
127    pub fn try_push(&mut self, value: T) -> Result<(), LimitedVecError> {
128        Self::validate_len(self.len() + 1)?;
129
130        self.0.push(value);
131        Ok(())
132    }
133
134    /// Appends values from slice to the end of vector.
135    pub fn try_extend_from_slice(&mut self, values: &[T]) -> Result<(), LimitedVecError>
136    where
137        T: Clone,
138    {
139        let new_len = self
140            .len()
141            .checked_add(values.len())
142            .ok_or(LimitedVecError)?;
143        Self::validate_len(new_len)?;
144
145        self.0.extend_from_slice(values);
146        Ok(())
147    }
148
149    /// Returns a slice reference to the vector contents.
150    pub fn as_slice(&self) -> &[T] {
151        self
152    }
153
154    /// Clones the limited vector into `Vec<T>`.
155    pub fn to_vec(&self) -> Vec<T>
156    where
157        T: Clone,
158    {
159        self.0.clone()
160    }
161
162    /// Converts the limited vector into its inner `Vec<T>`.
163    pub fn into_vec(self) -> Vec<T> {
164        self.0
165    }
166}
167
168impl<T, const N: usize> fmt::Display for LimitedVec<T, N>
169where
170    [T]: AsRef<[u8]>,
171{
172    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
173        let bytes = ByteSliceFormatter::Dynamic(self.0.as_slice().as_ref());
174
175        // FIXME: this hacky trick with a function is required
176        //        because of inability to put `format_args!(...)`
177        //        into a variable. It can be replaced with something
178        //        more straightforward when `formatting_options`
179        //        is stabilized.
180        //
181        // See:
182        // - https://doc.rust-lang.org/stable/std/macro.format_args.html#lifetime-limitation
183        // - https://doc.rust-lang.org/stable/std/fmt/struct.Formatter.html#method.with_options
184        let fmt_bytes = |f: &mut Formatter, bytes| {
185            if f.alternate() {
186                write!(f, "LimitedVec({bytes})")
187            } else {
188                write!(f, "{bytes}")
189            }
190        };
191
192        if let Some(precision) = f.precision() {
193            fmt_bytes(f, format_args!("{bytes:.precision$}"))
194        } else if f.sign_plus() {
195            fmt_bytes(f, format_args!("{bytes}"))
196        } else {
197            fmt_bytes(f, format_args!("{bytes:.8}"))
198        }
199    }
200}
201
202impl<T, const N: usize> fmt::Debug for LimitedVec<T, N>
203where
204    [T]: AsRef<[u8]>,
205{
206    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
207        fmt::Display::fmt(self, f)
208    }
209}
210
211/// Error type for limited vector overflowing.
212#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Display, Error)]
213#[display("{}", Self::MESSAGE)]
214pub struct LimitedVecError;
215
216impl LimitedVecError {
217    /// Static error message.
218    pub const MESSAGE: &str = "vector length limit is exceeded";
219
220    /// Converts the error into a static error message.
221    pub const fn as_str(&self) -> &'static str {
222        Self::MESSAGE
223    }
224}
225
226#[cfg(test)]
227mod test {
228    use super::LimitedVec;
229    use alloc::{string::String, vec, vec::Vec};
230    use core::convert::TryFrom;
231
232    const N: usize = 1000;
233    type TestBuffer = LimitedVec<u8, N>;
234    const M: usize = 64;
235    type SmallTestBuffer = LimitedVec<u8, M>;
236
237    #[test]
238    fn test_try_from() {
239        let v1 = vec![1; N];
240        let v2 = vec![1; N + 1];
241        let v3 = vec![1; N - 1];
242
243        let x = TestBuffer::try_from(v1).unwrap();
244        let _ = TestBuffer::try_from(v2).expect_err("Must be err because of size overflow");
245        let z = TestBuffer::try_from(v3).unwrap();
246
247        assert_eq!(x.len(), N);
248        assert_eq!(z.len(), N - 1);
249        assert_eq!(x[N / 2], 1);
250        assert_eq!(z[N / 2], 1);
251    }
252
253    #[test]
254    fn test_repeat() {
255        let x = LimitedVec::<u32, N>::repeat(0);
256        assert_eq!(x.len(), N);
257
258        let y = LimitedVec::<i32, 3>::repeat(-4);
259        assert_eq!(y.as_slice(), &[-4, -4, -4]);
260    }
261
262    #[test]
263    fn test_try_repeat() {
264        let x = LimitedVec::<String, N>::try_repeat(String::new(), N).unwrap();
265        assert!(
266            LimitedVec::<u64, N>::try_repeat(0, N + 1).is_err(),
267            "Must be error because of size overflow"
268        );
269        let y = LimitedVec::<char, 7>::try_repeat('@', 5).unwrap();
270        let z = LimitedVec::<Vec<u8>, N>::try_repeat(vec![], 0).unwrap();
271
272        assert_eq!(x.len(), N);
273        assert_eq!(z.len(), 0);
274        assert_eq!(x[N / 2], "");
275        assert_eq!(y.as_slice(), &['@', '@', '@', '@', '@']);
276    }
277
278    #[test]
279    fn test_full() {
280        let mut x = TestBuffer::try_from(vec![1; N]).unwrap();
281        let mut y = TestBuffer::try_from(vec![2; N / 2]).unwrap();
282        let mut z = TestBuffer::try_from(vec![3; 0]).unwrap();
283
284        x.try_extend_from_slice(&[1, 2, 3]).unwrap_err();
285        y.try_extend_from_slice(&[1, 2, 3]).unwrap();
286        z.try_extend_from_slice(&[1, 2, 3]).unwrap();
287
288        x.try_push(42).unwrap_err();
289        y.try_push(42).unwrap();
290        z.try_push(42).unwrap();
291
292        x.try_extend_from_slice(&[1, 2, 3]).unwrap_err();
293        y.try_extend_from_slice(&[1, 2, 3]).unwrap();
294        z.try_extend_from_slice(&[1, 2, 3]).unwrap();
295
296        z[0] = 0;
297
298        assert_eq!(&z.into_vec(), &[0, 2, 3, 42, 1, 2, 3]);
299        assert_eq!(TestBuffer::MAX_LEN, N);
300    }
301
302    #[test]
303    fn formatting_test() {
304        use alloc::format;
305
306        let buffer = SmallTestBuffer::try_from(b"abcdefghijklmnopqrstuvwxyz012345".to_vec())
307            .expect("String is 64 bytes");
308
309        // `Debug`/`Display`.
310        assert_eq!(
311            format!("{buffer:+?}"),
312            "0x6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435"
313        );
314        // `Debug`/`Display` with default precision.
315        assert_eq!(
316            format!("{buffer:?}"),
317            "0x6162636465666768..797a303132333435"
318        );
319        // `Debug`/`Display` with precision 0.
320        assert_eq!(format!("{buffer:.0?}"), "0x..");
321        // `Debug`/`Display` with precision 1.
322        assert_eq!(format!("{buffer:.1?}"), "0x61..35");
323        // `Debug`/`Display` with precision 2.
324        assert_eq!(format!("{buffer:.2?}"), "0x6162..3435");
325        // `Debug`/`Display` with precision 4.
326        assert_eq!(format!("{buffer:.4?}"), "0x61626364..32333435");
327        // `Debug`/`Display` with precision 15.
328        assert_eq!(
329            format!("{buffer:.15?}"),
330            "0x6162636465666768696a6b6c6d6e6f..72737475767778797a303132333435"
331        );
332        // `Debug`/`Display` with precision 30.
333        assert_eq!(
334            format!("{buffer:.30?}"),
335            "0x6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435"
336        );
337        // Alternate formatter with default precision.
338        assert_eq!(
339            format!("{buffer:#}"),
340            "LimitedVec(0x6162636465666768..797a303132333435)"
341        );
342        // Alternate formatter with max precision.
343        assert_eq!(
344            format!("{buffer:+#}"),
345            "LimitedVec(0x6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435)"
346        );
347        // Alternate formatter with precision 2.
348        assert_eq!(format!("{buffer:#.2}"), "LimitedVec(0x6162..3435)");
349    }
350}