1cbd624adSopenharmony_ci//! Simple stack-allocated vector.
2cbd624adSopenharmony_ci
3cbd624adSopenharmony_ci#![cfg(not(feature = "alloc"))]
4cbd624adSopenharmony_ci#![doc(hidden)]
5cbd624adSopenharmony_ci
6cbd624adSopenharmony_ciuse crate::bigint;
7cbd624adSopenharmony_ciuse core::{cmp, mem, ops, ptr, slice};
8cbd624adSopenharmony_ci
9cbd624adSopenharmony_ci/// Simple stack vector implementation.
10cbd624adSopenharmony_ci#[derive(Clone)]
11cbd624adSopenharmony_cipub struct StackVec {
12cbd624adSopenharmony_ci    /// The raw buffer for the elements.
13cbd624adSopenharmony_ci    data: [mem::MaybeUninit<bigint::Limb>; bigint::BIGINT_LIMBS],
14cbd624adSopenharmony_ci    /// The number of elements in the array (we never need more than u16::MAX).
15cbd624adSopenharmony_ci    length: u16,
16cbd624adSopenharmony_ci}
17cbd624adSopenharmony_ci
18cbd624adSopenharmony_ci#[allow(clippy::new_without_default)]
19cbd624adSopenharmony_ciimpl StackVec {
20cbd624adSopenharmony_ci    /// Construct an empty vector.
21cbd624adSopenharmony_ci    #[inline]
22cbd624adSopenharmony_ci    pub const fn new() -> Self {
23cbd624adSopenharmony_ci        Self {
24cbd624adSopenharmony_ci            length: 0,
25cbd624adSopenharmony_ci            data: [mem::MaybeUninit::uninit(); bigint::BIGINT_LIMBS],
26cbd624adSopenharmony_ci        }
27cbd624adSopenharmony_ci    }
28cbd624adSopenharmony_ci
29cbd624adSopenharmony_ci    /// Construct a vector from an existing slice.
30cbd624adSopenharmony_ci    #[inline]
31cbd624adSopenharmony_ci    pub fn try_from(x: &[bigint::Limb]) -> Option<Self> {
32cbd624adSopenharmony_ci        let mut vec = Self::new();
33cbd624adSopenharmony_ci        vec.try_extend(x)?;
34cbd624adSopenharmony_ci        Some(vec)
35cbd624adSopenharmony_ci    }
36cbd624adSopenharmony_ci
37cbd624adSopenharmony_ci    /// Sets the length of a vector.
38cbd624adSopenharmony_ci    ///
39cbd624adSopenharmony_ci    /// This will explicitly set the size of the vector, without actually
40cbd624adSopenharmony_ci    /// modifying its buffers, so it is up to the caller to ensure that the
41cbd624adSopenharmony_ci    /// vector is actually the specified size.
42cbd624adSopenharmony_ci    ///
43cbd624adSopenharmony_ci    /// # Safety
44cbd624adSopenharmony_ci    ///
45cbd624adSopenharmony_ci    /// Safe as long as `len` is less than `BIGINT_LIMBS`.
46cbd624adSopenharmony_ci    #[inline]
47cbd624adSopenharmony_ci    pub unsafe fn set_len(&mut self, len: usize) {
48cbd624adSopenharmony_ci        // Constant is `u16::MAX` for older Rustc versions.
49cbd624adSopenharmony_ci        debug_assert!(len <= 0xffff);
50cbd624adSopenharmony_ci        debug_assert!(len <= bigint::BIGINT_LIMBS);
51cbd624adSopenharmony_ci        self.length = len as u16;
52cbd624adSopenharmony_ci    }
53cbd624adSopenharmony_ci
54cbd624adSopenharmony_ci    /// The number of elements stored in the vector.
55cbd624adSopenharmony_ci    #[inline]
56cbd624adSopenharmony_ci    pub const fn len(&self) -> usize {
57cbd624adSopenharmony_ci        self.length as usize
58cbd624adSopenharmony_ci    }
59cbd624adSopenharmony_ci
60cbd624adSopenharmony_ci    /// If the vector is empty.
61cbd624adSopenharmony_ci    #[inline]
62cbd624adSopenharmony_ci    pub const fn is_empty(&self) -> bool {
63cbd624adSopenharmony_ci        self.len() == 0
64cbd624adSopenharmony_ci    }
65cbd624adSopenharmony_ci
66cbd624adSopenharmony_ci    /// The number of items the vector can hold.
67cbd624adSopenharmony_ci    #[inline]
68cbd624adSopenharmony_ci    pub const fn capacity(&self) -> usize {
69cbd624adSopenharmony_ci        bigint::BIGINT_LIMBS as usize
70cbd624adSopenharmony_ci    }
71cbd624adSopenharmony_ci
72cbd624adSopenharmony_ci    /// Append an item to the vector, without bounds checking.
73cbd624adSopenharmony_ci    ///
74cbd624adSopenharmony_ci    /// # Safety
75cbd624adSopenharmony_ci    ///
76cbd624adSopenharmony_ci    /// Safe if `self.len() < self.capacity()`.
77cbd624adSopenharmony_ci    #[inline]
78cbd624adSopenharmony_ci    pub unsafe fn push_unchecked(&mut self, value: bigint::Limb) {
79cbd624adSopenharmony_ci        debug_assert!(self.len() < self.capacity());
80cbd624adSopenharmony_ci        // SAFETY: safe, capacity is less than the current size.
81cbd624adSopenharmony_ci        unsafe {
82cbd624adSopenharmony_ci            ptr::write(self.as_mut_ptr().add(self.len()), value);
83cbd624adSopenharmony_ci            self.length += 1;
84cbd624adSopenharmony_ci        }
85cbd624adSopenharmony_ci    }
86cbd624adSopenharmony_ci
87cbd624adSopenharmony_ci    /// Append an item to the vector.
88cbd624adSopenharmony_ci    #[inline]
89cbd624adSopenharmony_ci    pub fn try_push(&mut self, value: bigint::Limb) -> Option<()> {
90cbd624adSopenharmony_ci        if self.len() < self.capacity() {
91cbd624adSopenharmony_ci            // SAFETY: safe, capacity is less than the current size.
92cbd624adSopenharmony_ci            unsafe { self.push_unchecked(value) };
93cbd624adSopenharmony_ci            Some(())
94cbd624adSopenharmony_ci        } else {
95cbd624adSopenharmony_ci            None
96cbd624adSopenharmony_ci        }
97cbd624adSopenharmony_ci    }
98cbd624adSopenharmony_ci
99cbd624adSopenharmony_ci    /// Remove an item from the end of a vector, without bounds checking.
100cbd624adSopenharmony_ci    ///
101cbd624adSopenharmony_ci    /// # Safety
102cbd624adSopenharmony_ci    ///
103cbd624adSopenharmony_ci    /// Safe if `self.len() > 0`.
104cbd624adSopenharmony_ci    #[inline]
105cbd624adSopenharmony_ci    pub unsafe fn pop_unchecked(&mut self) -> bigint::Limb {
106cbd624adSopenharmony_ci        debug_assert!(!self.is_empty());
107cbd624adSopenharmony_ci        // SAFETY: safe if `self.length > 0`.
108cbd624adSopenharmony_ci        // We have a trivial drop and copy, so this is safe.
109cbd624adSopenharmony_ci        self.length -= 1;
110cbd624adSopenharmony_ci        unsafe { ptr::read(self.as_mut_ptr().add(self.len())) }
111cbd624adSopenharmony_ci    }
112cbd624adSopenharmony_ci
113cbd624adSopenharmony_ci    /// Remove an item from the end of the vector and return it, or None if empty.
114cbd624adSopenharmony_ci    #[inline]
115cbd624adSopenharmony_ci    pub fn pop(&mut self) -> Option<bigint::Limb> {
116cbd624adSopenharmony_ci        if self.is_empty() {
117cbd624adSopenharmony_ci            None
118cbd624adSopenharmony_ci        } else {
119cbd624adSopenharmony_ci            // SAFETY: safe, since `self.len() > 0`.
120cbd624adSopenharmony_ci            unsafe { Some(self.pop_unchecked()) }
121cbd624adSopenharmony_ci        }
122cbd624adSopenharmony_ci    }
123cbd624adSopenharmony_ci
124cbd624adSopenharmony_ci    /// Add items from a slice to the vector, without bounds checking.
125cbd624adSopenharmony_ci    ///
126cbd624adSopenharmony_ci    /// # Safety
127cbd624adSopenharmony_ci    ///
128cbd624adSopenharmony_ci    /// Safe if `self.len() + slc.len() <= self.capacity()`.
129cbd624adSopenharmony_ci    #[inline]
130cbd624adSopenharmony_ci    pub unsafe fn extend_unchecked(&mut self, slc: &[bigint::Limb]) {
131cbd624adSopenharmony_ci        let index = self.len();
132cbd624adSopenharmony_ci        let new_len = index + slc.len();
133cbd624adSopenharmony_ci        debug_assert!(self.len() + slc.len() <= self.capacity());
134cbd624adSopenharmony_ci        let src = slc.as_ptr();
135cbd624adSopenharmony_ci        // SAFETY: safe if `self.len() + slc.len() <= self.capacity()`.
136cbd624adSopenharmony_ci        unsafe {
137cbd624adSopenharmony_ci            let dst = self.as_mut_ptr().add(index);
138cbd624adSopenharmony_ci            ptr::copy_nonoverlapping(src, dst, slc.len());
139cbd624adSopenharmony_ci            self.set_len(new_len);
140cbd624adSopenharmony_ci        }
141cbd624adSopenharmony_ci    }
142cbd624adSopenharmony_ci
143cbd624adSopenharmony_ci    /// Copy elements from a slice and append them to the vector.
144cbd624adSopenharmony_ci    #[inline]
145cbd624adSopenharmony_ci    pub fn try_extend(&mut self, slc: &[bigint::Limb]) -> Option<()> {
146cbd624adSopenharmony_ci        if self.len() + slc.len() <= self.capacity() {
147cbd624adSopenharmony_ci            // SAFETY: safe, since `self.len() + slc.len() <= self.capacity()`.
148cbd624adSopenharmony_ci            unsafe { self.extend_unchecked(slc) };
149cbd624adSopenharmony_ci            Some(())
150cbd624adSopenharmony_ci        } else {
151cbd624adSopenharmony_ci            None
152cbd624adSopenharmony_ci        }
153cbd624adSopenharmony_ci    }
154cbd624adSopenharmony_ci
155cbd624adSopenharmony_ci    /// Truncate vector to new length, dropping any items after `len`.
156cbd624adSopenharmony_ci    ///
157cbd624adSopenharmony_ci    /// # Safety
158cbd624adSopenharmony_ci    ///
159cbd624adSopenharmony_ci    /// Safe as long as `len <= self.capacity()`.
160cbd624adSopenharmony_ci    unsafe fn truncate_unchecked(&mut self, len: usize) {
161cbd624adSopenharmony_ci        debug_assert!(len <= self.capacity());
162cbd624adSopenharmony_ci        self.length = len as u16;
163cbd624adSopenharmony_ci    }
164cbd624adSopenharmony_ci
165cbd624adSopenharmony_ci    /// Resize the buffer, without bounds checking.
166cbd624adSopenharmony_ci    ///
167cbd624adSopenharmony_ci    /// # Safety
168cbd624adSopenharmony_ci    ///
169cbd624adSopenharmony_ci    /// Safe as long as `len <= self.capacity()`.
170cbd624adSopenharmony_ci    #[inline]
171cbd624adSopenharmony_ci    pub unsafe fn resize_unchecked(&mut self, len: usize, value: bigint::Limb) {
172cbd624adSopenharmony_ci        debug_assert!(len <= self.capacity());
173cbd624adSopenharmony_ci        let old_len = self.len();
174cbd624adSopenharmony_ci        if len > old_len {
175cbd624adSopenharmony_ci            // We have a trivial drop, so there's no worry here.
176cbd624adSopenharmony_ci            // Just, don't set the length until all values have been written,
177cbd624adSopenharmony_ci            // so we don't accidentally read uninitialized memory.
178cbd624adSopenharmony_ci
179cbd624adSopenharmony_ci            // SAFETY: safe if `len < self.capacity()`.
180cbd624adSopenharmony_ci            let count = len - old_len;
181cbd624adSopenharmony_ci            for index in 0..count {
182cbd624adSopenharmony_ci                unsafe {
183cbd624adSopenharmony_ci                    let dst = self.as_mut_ptr().add(old_len + index);
184cbd624adSopenharmony_ci                    ptr::write(dst, value);
185cbd624adSopenharmony_ci                }
186cbd624adSopenharmony_ci            }
187cbd624adSopenharmony_ci            self.length = len as u16;
188cbd624adSopenharmony_ci        } else {
189cbd624adSopenharmony_ci            // SAFETY: safe since `len < self.len()`.
190cbd624adSopenharmony_ci            unsafe { self.truncate_unchecked(len) };
191cbd624adSopenharmony_ci        }
192cbd624adSopenharmony_ci    }
193cbd624adSopenharmony_ci
194cbd624adSopenharmony_ci    /// Try to resize the buffer.
195cbd624adSopenharmony_ci    ///
196cbd624adSopenharmony_ci    /// If the new length is smaller than the current length, truncate
197cbd624adSopenharmony_ci    /// the input. If it's larger, then append elements to the buffer.
198cbd624adSopenharmony_ci    #[inline]
199cbd624adSopenharmony_ci    pub fn try_resize(&mut self, len: usize, value: bigint::Limb) -> Option<()> {
200cbd624adSopenharmony_ci        if len > self.capacity() {
201cbd624adSopenharmony_ci            None
202cbd624adSopenharmony_ci        } else {
203cbd624adSopenharmony_ci            // SAFETY: safe, since `len <= self.capacity()`.
204cbd624adSopenharmony_ci            unsafe { self.resize_unchecked(len, value) };
205cbd624adSopenharmony_ci            Some(())
206cbd624adSopenharmony_ci        }
207cbd624adSopenharmony_ci    }
208cbd624adSopenharmony_ci
209cbd624adSopenharmony_ci    // HI
210cbd624adSopenharmony_ci
211cbd624adSopenharmony_ci    /// Get the high 64 bits from the vector.
212cbd624adSopenharmony_ci    #[inline(always)]
213cbd624adSopenharmony_ci    pub fn hi64(&self) -> (u64, bool) {
214cbd624adSopenharmony_ci        bigint::hi64(self)
215cbd624adSopenharmony_ci    }
216cbd624adSopenharmony_ci
217cbd624adSopenharmony_ci    // FROM
218cbd624adSopenharmony_ci
219cbd624adSopenharmony_ci    /// Create StackVec from u64 value.
220cbd624adSopenharmony_ci    #[inline(always)]
221cbd624adSopenharmony_ci    pub fn from_u64(x: u64) -> Self {
222cbd624adSopenharmony_ci        bigint::from_u64(x)
223cbd624adSopenharmony_ci    }
224cbd624adSopenharmony_ci
225cbd624adSopenharmony_ci    // MATH
226cbd624adSopenharmony_ci
227cbd624adSopenharmony_ci    /// Normalize the integer, so any leading zero values are removed.
228cbd624adSopenharmony_ci    #[inline]
229cbd624adSopenharmony_ci    pub fn normalize(&mut self) {
230cbd624adSopenharmony_ci        bigint::normalize(self)
231cbd624adSopenharmony_ci    }
232cbd624adSopenharmony_ci
233cbd624adSopenharmony_ci    /// Get if the big integer is normalized.
234cbd624adSopenharmony_ci    #[inline]
235cbd624adSopenharmony_ci    pub fn is_normalized(&self) -> bool {
236cbd624adSopenharmony_ci        bigint::is_normalized(self)
237cbd624adSopenharmony_ci    }
238cbd624adSopenharmony_ci
239cbd624adSopenharmony_ci    /// AddAssign small integer.
240cbd624adSopenharmony_ci    #[inline]
241cbd624adSopenharmony_ci    pub fn add_small(&mut self, y: bigint::Limb) -> Option<()> {
242cbd624adSopenharmony_ci        bigint::small_add(self, y)
243cbd624adSopenharmony_ci    }
244cbd624adSopenharmony_ci
245cbd624adSopenharmony_ci    /// MulAssign small integer.
246cbd624adSopenharmony_ci    #[inline]
247cbd624adSopenharmony_ci    pub fn mul_small(&mut self, y: bigint::Limb) -> Option<()> {
248cbd624adSopenharmony_ci        bigint::small_mul(self, y)
249cbd624adSopenharmony_ci    }
250cbd624adSopenharmony_ci}
251cbd624adSopenharmony_ci
252cbd624adSopenharmony_ciimpl PartialEq for StackVec {
253cbd624adSopenharmony_ci    #[inline]
254cbd624adSopenharmony_ci    #[allow(clippy::op_ref)]
255cbd624adSopenharmony_ci    fn eq(&self, other: &Self) -> bool {
256cbd624adSopenharmony_ci        use core::ops::Deref;
257cbd624adSopenharmony_ci        self.len() == other.len() && self.deref() == other.deref()
258cbd624adSopenharmony_ci    }
259cbd624adSopenharmony_ci}
260cbd624adSopenharmony_ci
261cbd624adSopenharmony_ciimpl Eq for StackVec {
262cbd624adSopenharmony_ci}
263cbd624adSopenharmony_ci
264cbd624adSopenharmony_ciimpl cmp::PartialOrd for StackVec {
265cbd624adSopenharmony_ci    #[inline]
266cbd624adSopenharmony_ci    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
267cbd624adSopenharmony_ci        Some(bigint::compare(self, other))
268cbd624adSopenharmony_ci    }
269cbd624adSopenharmony_ci}
270cbd624adSopenharmony_ci
271cbd624adSopenharmony_ciimpl cmp::Ord for StackVec {
272cbd624adSopenharmony_ci    #[inline]
273cbd624adSopenharmony_ci    fn cmp(&self, other: &Self) -> cmp::Ordering {
274cbd624adSopenharmony_ci        bigint::compare(self, other)
275cbd624adSopenharmony_ci    }
276cbd624adSopenharmony_ci}
277cbd624adSopenharmony_ci
278cbd624adSopenharmony_ciimpl ops::Deref for StackVec {
279cbd624adSopenharmony_ci    type Target = [bigint::Limb];
280cbd624adSopenharmony_ci    #[inline]
281cbd624adSopenharmony_ci    fn deref(&self) -> &[bigint::Limb] {
282cbd624adSopenharmony_ci        // SAFETY: safe since `self.data[..self.len()]` must be initialized
283cbd624adSopenharmony_ci        // and `self.len() <= self.capacity()`.
284cbd624adSopenharmony_ci        unsafe {
285cbd624adSopenharmony_ci            let ptr = self.data.as_ptr() as *const bigint::Limb;
286cbd624adSopenharmony_ci            slice::from_raw_parts(ptr, self.len())
287cbd624adSopenharmony_ci        }
288cbd624adSopenharmony_ci    }
289cbd624adSopenharmony_ci}
290cbd624adSopenharmony_ci
291cbd624adSopenharmony_ciimpl ops::DerefMut for StackVec {
292cbd624adSopenharmony_ci    #[inline]
293cbd624adSopenharmony_ci    fn deref_mut(&mut self) -> &mut [bigint::Limb] {
294cbd624adSopenharmony_ci        // SAFETY: safe since `self.data[..self.len()]` must be initialized
295cbd624adSopenharmony_ci        // and `self.len() <= self.capacity()`.
296cbd624adSopenharmony_ci        unsafe {
297cbd624adSopenharmony_ci            let ptr = self.data.as_mut_ptr() as *mut bigint::Limb;
298cbd624adSopenharmony_ci            slice::from_raw_parts_mut(ptr, self.len())
299cbd624adSopenharmony_ci        }
300cbd624adSopenharmony_ci    }
301cbd624adSopenharmony_ci}
302cbd624adSopenharmony_ci
303cbd624adSopenharmony_ciimpl ops::MulAssign<&[bigint::Limb]> for StackVec {
304cbd624adSopenharmony_ci    #[inline]
305cbd624adSopenharmony_ci    fn mul_assign(&mut self, rhs: &[bigint::Limb]) {
306cbd624adSopenharmony_ci        bigint::large_mul(self, rhs).unwrap();
307cbd624adSopenharmony_ci    }
308cbd624adSopenharmony_ci}
309