dashu_int/
repr.rs

1//! Underlying representation of big integers.
2
3use crate::{
4    arch::word::{DoubleWord, Word},
5    buffer::Buffer,
6    primitive::{double_word, split_dword},
7    Sign,
8};
9use core::{
10    fmt::{self, Write},
11    hash::{Hash, Hasher},
12    hint::unreachable_unchecked,
13    mem,
14    num::NonZeroIsize,
15    ptr::{self, NonNull},
16    slice,
17};
18use static_assertions::const_assert_eq;
19
20/// This union contains the raw representation of words, the words are either inlined
21/// or on the heap. The flag used to distinguishing them is the `len` field of the buffer.
22#[repr(C)]
23union ReprData {
24    inline: [Word; 2],        // lo, hi
25    heap: (*mut Word, usize), // ptr, len
26}
27
28/// Internal representation for big integers.
29///
30/// It's optimized so that small integers (single or double words) will not be allocated on heap.
31/// When the data is allocated on the heap, it can be casted to [Buffer] efficiently, but modifying
32/// the buffer inplace is not allowed because that can break the rule on the `capacity` field.
33///
34/// To modified the internal data, one must convert the Repr into either [TypedRepr](enum, owning the data)
35/// or [Buffer](raw heap buffer). To access the internal data, one must use [TypedReprRef](enum, reference)
36/// or [slice][Repr::as_slice] protocol.
37#[repr(C)]
38pub struct Repr {
39    /// The words in the `data` field are ordered from the least significant to the most significant.
40    data: ReprData,
41
42    /// The capacity is guaranteed to be not zero so that it provides a niche value for layout optimization.
43    ///
44    /// How to intepret the `data` field:
45    /// - `capacity` = 1: the words are inlined and the high word is 0. (including the case where low word is also 0)
46    /// - `capacity` = 2: the words are inlined
47    /// - `capacity` >= 3: the words are on allocated on the heap. In this case, data.len >= 3 will also be forced.
48    /// - `capacity` < 0: similiar to the cases above, but negative capacity value is used to mark the integer is negative.
49    ///     Note that in this case the inlined value is not allowed to be zero. (zero must have a positive sign)
50    capacity: NonZeroIsize,
51}
52
53// right now on all supported architectures, Word = usize. However, for cases where
54// Word > usize, an extra padding in Buffer will be necessary for this equality to hold
55const_assert_eq!(mem::size_of::<Buffer>(), mem::size_of::<Repr>());
56
57// make sure the layout optimization is effective
58const_assert_eq!(mem::size_of::<Repr>(), mem::size_of::<Option<Repr>>());
59
60// SAFETY: the pointer to the allocated space is uniquely owned by this struct.
61unsafe impl Send for Repr {}
62
63// SAFETY: we don't provide interior mutability for Repr and Buffer
64unsafe impl Sync for Repr {}
65
66/// A strong typed safe representation of a `Repr` without sign
67#[derive(Clone)]
68pub enum TypedRepr {
69    Small(DoubleWord),
70    Large(Buffer),
71}
72
73/// A strong typed safe representation of a reference to `Repr` without sign
74#[derive(Clone, Copy, PartialEq, Eq)]
75pub enum TypedReprRef<'a> {
76    RefSmall(DoubleWord),
77    RefLarge(&'a [Word]),
78}
79
80impl Repr {
81    /// Get the length of the number (in `Word`s), return 0 when the number is zero.
82    #[inline]
83    pub const fn len(&self) -> usize {
84        // SAFETY: the capacity is checked before accessing the fields.
85        //         see the documentation for the `capacity` fields for invariants.
86        unsafe {
87            match self.capacity() {
88                0 => unreachable_unchecked(),
89                1 => (self.data.inline[0] != 0) as usize,
90                2 => 2,
91                _ => self.data.heap.1,
92            }
93        }
94    }
95
96    /// Get the capacity of the representation (in `Word`s)
97    ///
98    /// It will not be zero even if the underlying number is zero.
99    #[inline]
100    pub const fn capacity(&self) -> usize {
101        self.capacity.get().unsigned_abs()
102    }
103
104    /// Get the sign of the repr
105    #[inline]
106    pub const fn sign(&self) -> Sign {
107        if self.capacity.get() > 0 {
108            Sign::Positive
109        } else {
110            Sign::Negative
111        }
112    }
113
114    /// Get the capacity of Repr and sign simultaneously
115    #[inline]
116    pub const fn sign_capacity(&self) -> (usize, Sign) {
117        if self.capacity.get() > 0 {
118            (self.capacity.get() as usize, Sign::Positive)
119        } else {
120            // wrapping will never happen because MAX_CAPACITY < isize::MAX
121            (self.capacity.get().wrapping_neg() as usize, Sign::Negative)
122        }
123    }
124
125    /// Set the sign flag and return the changed representation. The sign will not
126    /// be flipped if self is zero
127    #[inline]
128    pub const fn with_sign(mut self, sign: Sign) -> Self {
129        let is_positive = match sign {
130            Sign::Positive => true,
131            Sign::Negative => false,
132        };
133        if !self.is_zero() && (is_positive ^ (self.capacity.get() > 0)) {
134            // SAFETY: capacity is not allowed to be zero
135            self.capacity = unsafe { NonZeroIsize::new_unchecked(-self.capacity.get()) }
136        }
137        self
138    }
139
140    /// Cast the reference of `Repr` to a strong typed representation, assuming the underlying data is unsigned.
141    /// Panics if the `capacity` is negative
142    #[rustversion::attr(since(1.64), const)]
143    #[inline]
144    pub fn as_typed(&self) -> TypedReprRef<'_> {
145        let (sign, typed) = self.as_sign_typed();
146        match sign {
147            // sign check
148            Sign::Positive => {}
149            Sign::Negative => unreachable!(),
150        }
151
152        typed
153    }
154
155    /// Cast the reference of `Repr` to a strong typed representation, and return with the sign.
156    #[rustversion::attr(since(1.64), const)]
157    #[inline]
158    pub fn as_sign_typed(&self) -> (Sign, TypedReprRef<'_>) {
159        let (abs_capacity, sign) = self.sign_capacity();
160
161        // SAFETY: the capacity is checked before accessing the fields.
162        //         see the documentation for the `capacity` fields for invariants.
163        let typed = unsafe {
164            match abs_capacity {
165                0 => unreachable_unchecked(),
166                1 | 2 => {
167                    TypedReprRef::RefSmall(double_word(self.data.inline[0], self.data.inline[1]))
168                }
169                _ => TypedReprRef::RefLarge(slice::from_raw_parts(
170                    // need Rust 1.64 for const
171                    self.data.heap.0,
172                    self.data.heap.1,
173                )),
174            }
175        };
176        (sign, typed)
177    }
178
179    /// Cast the `Repr` to a strong typed representation, assuming the underlying data is unsigned.
180    ///
181    /// # Panics
182    ///
183    /// Panics if the `capacity` is negative
184    #[inline]
185    pub fn into_typed(self) -> TypedRepr {
186        debug_assert!(self.capacity.get() > 0);
187
188        // SAFETY: the capacity is checked before accessing the fields.
189        //         see the documentation for the `capacity` fields for invariants.
190        unsafe {
191            match self.capacity.get() {
192                0 => unreachable_unchecked(),
193                1 | 2 => TypedRepr::Small(double_word(self.data.inline[0], self.data.inline[1])),
194                _ => {
195                    // SAFETY: An `Buffer` and `Repr` have the same layout
196                    //     and we have made sure that the data is allocated on heap
197                    TypedRepr::Large(mem::transmute(self))
198                }
199            }
200        }
201    }
202
203    /// Cast the `Repr` to a strong typed representation and return with the sign.
204    #[inline]
205    pub fn into_sign_typed(mut self) -> (Sign, TypedRepr) {
206        let (abs_capacity, sign) = self.sign_capacity();
207        // SAFETY: capacity != 0 is an invariant
208        self.capacity = unsafe { NonZeroIsize::new_unchecked(abs_capacity as isize) };
209        (sign, self.into_typed())
210    }
211
212    /// Get a reference to the words in the `Repr`
213    ///
214    /// # Panics
215    ///
216    /// Panics if the `capacity` is negative
217    #[inline]
218    pub fn as_slice(&self) -> &[Word] {
219        let (sign, slice) = self.as_sign_slice();
220        assert!(sign == Sign::Positive);
221        slice
222    }
223
224    /// Get a reference to the words in the `Repr`, together with the sign.
225    pub fn as_sign_slice(&self) -> (Sign, &[Word]) {
226        let (capacity, sign) = self.sign_capacity();
227
228        // SAFETY: the capacity is checked before accessing the fields.
229        //         see the documentation for the `capacity` fields for invariants.
230        let words = unsafe {
231            match capacity {
232                0 => unreachable_unchecked(),
233                1 => {
234                    if self.data.inline[0] == 0 {
235                        &[]
236                    } else {
237                        &self.data.inline[..1]
238                    }
239                }
240                2 => &self.data.inline,
241                _ => slice::from_raw_parts(self.data.heap.0, self.data.heap.1),
242            }
243        };
244        (sign, words)
245    }
246
247    #[cfg(feature = "zeroize")]
248    /// Get all the allocated space as a mutable slice
249    pub fn as_full_slice(&mut self) -> &mut [Word] {
250        // SAFETY: the capacity is checked before accessing the union fields.
251        //         see the documentation for the `capacity` fields for invariants.
252        unsafe {
253            let capacity = self.capacity();
254            if capacity <= 2 {
255                &mut self.data.inline
256            } else {
257                slice::from_raw_parts_mut(self.data.heap.0, capacity)
258            }
259        }
260    }
261
262    /// Creates a `Repr` with a single word
263    #[inline]
264    pub const fn from_word(n: Word) -> Self {
265        Repr {
266            data: ReprData { inline: [n, 0] },
267            // SAFETY: it's safe. The unsafe constructor is necessary
268            //         because it's in a const context.
269            capacity: unsafe { NonZeroIsize::new_unchecked(1) },
270        }
271    }
272
273    /// Creates a `Repr` with a double word
274    #[inline]
275    pub const fn from_dword(n: DoubleWord) -> Self {
276        let (lo, hi) = split_dword(n);
277        Repr {
278            data: ReprData { inline: [lo, hi] },
279            // SAFETY: it's safe. The value is either 1 or 2.
280            capacity: unsafe { NonZeroIsize::new_unchecked(1 + (hi != 0) as isize) },
281        }
282    }
283
284    /// Creates a `Repr` with a reference to static word array.
285    ///
286    /// This method is unsafe, because the caller must make sure that
287    /// the created instance is immutable, and drop() must not be called.
288    #[inline]
289    pub const unsafe fn from_static_words(words: &'static [Word]) -> Repr {
290        match words {
291            &[] => Self::zero(),
292            &[n] => Self::from_word(n),
293            &[lo, hi] => {
294                assert!(hi > 0);
295                Self::from_dword(double_word(lo, hi))
296            }
297            large => {
298                // this condition is always true, use this expression because unwrap() is not const
299                if let Some(n) = large.last() {
300                    assert!(*n != 0, "the array input must be normalized.");
301                }
302
303                let ptr = large.as_ptr() as _;
304                Self {
305                    data: ReprData {
306                        heap: (ptr, large.len()),
307                    },
308                    capacity: NonZeroIsize::new_unchecked(large.len() as _),
309                }
310            }
311        }
312    }
313
314    /// Create a `Repr` with a buffer allocated on heap. The leading zeros in the buffer
315    /// will be trimmed and the buffer will be shrunk if there is exceeded capacity.
316    pub fn from_buffer(mut buffer: Buffer) -> Self {
317        buffer.pop_zeros();
318
319        match buffer.len() {
320            0 => Self::from_word(0),
321            1 => Self::from_word(buffer[0]),
322            2 => Self::from_dword(double_word(buffer[0], buffer[1])),
323            _ => {
324                // If the Buffer was allocated with `Buffer::allocate(n)`
325                // and the normalized length is between `n - 2` and `n + 2`
326                // (or even approximately between `0.9 * n` and `1.125 * n`),
327                // there will be no reallocation here.
328                buffer.shrink_to_fit();
329
330                // SAFETY: the length has been checked and capacity >= lenght,
331                //         so capacity is nonzero and larger than 2
332                unsafe { mem::transmute(buffer) }
333            }
334        }
335    }
336
337    /// Create a [Repr] cloned from a reference to another [Repr]
338    pub fn from_ref(tref: TypedReprRef) -> Self {
339        match tref {
340            TypedReprRef::RefSmall(dw) => Self::from_dword(dw),
341            TypedReprRef::RefLarge(words) => Self::from_buffer(Buffer::from(words)),
342        }
343    }
344
345    /// Cast the `Repr` to a [Buffer] instance, assuming the underlying data is unsigned.
346    ///
347    /// # Panics
348    ///
349    /// Panics if the `capacity` is negative
350    pub fn into_buffer(self) -> Buffer {
351        debug_assert!(self.capacity.get() > 0); // invariant
352
353        // SAFETY: the capacity is checked before accessing the union fields.
354        //         see the documentation for the `capacity` fields for invariants.
355        unsafe {
356            match self.capacity.get() {
357                0 => unreachable_unchecked(),
358                1 => {
359                    let mut buffer = Buffer::allocate(1);
360                    if self.data.inline[0] != 0 {
361                        buffer.push(self.data.inline[0]);
362                    }
363                    buffer
364                }
365                2 => {
366                    debug_assert!(self.data.inline[1] != 0); // invariant
367                    let mut buffer = Buffer::allocate(2);
368                    buffer.push(self.data.inline[0]);
369                    buffer.push(self.data.inline[1]);
370                    buffer
371                }
372                _ => {
373                    // SAFETY: An `Buffer` and `Repr` have the same layout
374                    //     and we have made sure that the data is allocated on heap
375                    mem::transmute(self)
376                }
377            }
378        }
379    }
380
381    /// Creates a `Repr` with value 0
382    #[inline]
383    pub const fn zero() -> Self {
384        Self::from_word(0)
385    }
386
387    /// Check if the underlying value is zero
388    #[inline]
389    pub const fn is_zero(&self) -> bool {
390        // SAFETY: accessing the union field is safe because the
391        //         first condition is checked before access
392        self.capacity() == 1 && unsafe { self.data.inline[0] == 0 }
393    }
394
395    /// Creates a `Repr` with value 1
396    #[inline]
397    pub const fn one() -> Self {
398        Self::from_word(1)
399    }
400
401    /// Check if the underlying value is zero
402    #[inline]
403    pub const fn is_one(&self) -> bool {
404        // SAFETY: accessing the union field is safe because the
405        //         first condition is checked before access
406        self.capacity.get() == 1 && unsafe { self.data.inline[0] == 1 }
407    }
408
409    /// Creates a `Repr` with value -1
410    #[inline]
411    pub const fn neg_one() -> Self {
412        Self::from_word(1).with_sign(Sign::Negative)
413    }
414
415    /// Flip the sign bit of the Repr and return it
416    pub const fn neg(mut self) -> Self {
417        if !self.is_zero() {
418            // SAFETY: the capacity != 0 is an invariant
419            self.capacity = unsafe { NonZeroIsize::new_unchecked(-self.capacity.get()) }
420        }
421        self
422    }
423
424    /// Returns a number representing sign of self.
425    ///
426    /// * [Self::zero] if the number is zero
427    /// * [Self::one] if the number is positive
428    /// * [Self::neg_one] if the number is negative
429    pub const fn signum(&self) -> Self {
430        if self.is_zero() {
431            Self::zero()
432        } else if self.capacity.get() < 0 {
433            Self::neg_one()
434        } else {
435            Self::one()
436        }
437    }
438}
439
440// Cloning for Repr is written in a verbose way because it's performance critical.
441impl Clone for Repr {
442    fn clone(&self) -> Self {
443        let (capacity, sign) = self.sign_capacity();
444
445        // SAFETY: see the comments inside the block
446        let new = unsafe {
447            // inline the data if the length is less than 3
448            // SAFETY: we check the capacity before accessing the variants
449            if capacity <= 2 {
450                Repr {
451                    data: ReprData {
452                        inline: self.data.inline,
453                    },
454                    // SAFETY: the capacity is from self, which guarantees it to be zero
455                    capacity: NonZeroIsize::new_unchecked(capacity as isize),
456                }
457            } else {
458                let (ptr, len) = self.data.heap;
459                // SAFETY: len is at least 2 when it's heap allocated (invariant of Repr)
460                let mut new_buffer = Buffer::allocate(len);
461                new_buffer.push_slice(slice::from_raw_parts(ptr, len));
462
463                // SAFETY: abs(self.capacity) >= 3 => self.data.len >= 3
464                // so the capacity and len of new_buffer will be both >= 3
465                mem::transmute(new_buffer)
466            }
467        };
468        new.with_sign(sign)
469    }
470
471    fn clone_from(&mut self, src: &Self) {
472        let (src_cap, src_sign) = src.sign_capacity();
473        let (cap, _) = self.sign_capacity();
474
475        // SAFETY: see the comments inside the block
476        unsafe {
477            // shortcut for inlined data
478            if src_cap <= 2 {
479                if cap > 2 {
480                    // release the old buffer if necessary
481                    // SAFETY: self.data.heap.0 must be valid pointer if cap > 2
482                    Buffer::deallocate_raw(NonNull::new_unchecked(self.data.heap.0), cap);
483                }
484                self.data.inline = src.data.inline;
485                self.capacity = src.capacity;
486                return;
487            }
488
489            // SAFETY: we checked that abs(src.capacity) > 2
490            let (src_ptr, src_len) = src.data.heap;
491            debug_assert!(src_len >= 3);
492
493            // check if we need reallocation, it happens when capacity is too small or too large
494            if cap < src_len || cap > Buffer::max_compact_capacity(src_len) {
495                if cap > 2 {
496                    // release the old buffer if necessary
497                    Buffer::deallocate_raw(NonNull::new_unchecked(self.data.heap.0), cap);
498                }
499
500                let new_cap = Buffer::default_capacity(src_len);
501                let new_ptr = Buffer::allocate_raw(new_cap);
502                self.data.heap.0 = new_ptr.as_ptr();
503                // SAFETY: allocate_raw will allocates at least 2 words even if src_len is 0
504                self.capacity = NonZeroIsize::new_unchecked(new_cap as isize);
505            }
506
507            // SAFETY: src.ptr and self.ptr are both properly allocated by `Buffer::allocate()`.
508            //         src.ptr and self.ptr cannot alias, because the ptr should be uniquely owned by the Buffer
509            ptr::copy_nonoverlapping(src_ptr, self.data.heap.0, src_len);
510
511            // update length and sign
512            self.data.heap.1 = src_len;
513            if (src_sign == Sign::Positive) ^ (self.capacity.get() > 0) {
514                self.capacity = NonZeroIsize::new_unchecked(-self.capacity.get());
515            }
516        }
517    }
518}
519
520impl Drop for Repr {
521    fn drop(&mut self) {
522        let cap = self.capacity();
523        if cap > 2 {
524            // SAFETY: the data is heap allocated when abs(capacity) > 2 (invariant of Repr)
525            unsafe {
526                Buffer::deallocate_raw(NonNull::new_unchecked(self.data.heap.0), cap);
527            }
528        }
529    }
530}
531
532impl PartialEq for Repr {
533    #[inline]
534    fn eq(&self, other: &Self) -> bool {
535        self.as_sign_slice() == other.as_sign_slice()
536    }
537}
538impl Eq for Repr {}
539
540impl fmt::Debug for Repr {
541    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542        let (sign, words) = self.as_sign_slice();
543        if let Sign::Negative = sign {
544            f.write_char('-')?;
545        }
546        f.debug_list().entries(words).finish()
547    }
548}
549
550impl Hash for Repr {
551    fn hash<H: Hasher>(&self, state: &mut H) {
552        let (sign, arr) = self.as_sign_slice();
553        sign.hash(state);
554        (*arr).hash(state);
555    }
556}
557
558impl TypedRepr {
559    /// Convert a reference of `TypedRef` to `TypedReprRef`
560    #[inline]
561    pub fn as_ref(&self) -> TypedReprRef {
562        match self {
563            Self::Small(dword) => TypedReprRef::RefSmall(*dword),
564            Self::Large(words) => TypedReprRef::RefLarge(words),
565        }
566    }
567}
568
569impl<'a> TypedReprRef<'a> {
570    /// Get the length of the number in words, return 0 when the number is zero.
571    #[inline]
572    pub fn len(&self) -> usize {
573        match self {
574            Self::RefSmall(dword) => {
575                if *dword == 0 {
576                    0
577                } else if *dword <= Word::MAX as DoubleWord {
578                    1
579                } else {
580                    2
581                }
582            }
583            Self::RefLarge(words) => words.len(),
584        }
585    }
586
587    /// This operation just return a copy of `self`. It's meant to be used in macros.
588    #[inline]
589    pub fn as_ref(&self) -> TypedReprRef {
590        *self
591    }
592}
593
594#[cfg(test)]
595mod tests {
596    use super::*;
597    use crate::primitive::WORD_BITS_USIZE;
598
599    #[test]
600    fn test_inline() {
601        let repr = Repr::zero();
602        assert_eq!(repr.capacity(), 1);
603        assert_eq!(repr.len(), 0);
604
605        let repr = Repr::from_word(123);
606        assert_eq!(repr.capacity(), 1);
607        assert_eq!(repr.len(), 1);
608
609        let repr = Repr::from_dword(123 << WORD_BITS_USIZE);
610        assert_eq!(repr.capacity(), 2);
611        assert_eq!(repr.len(), 2);
612    }
613
614    #[test]
615    fn test_deref() {
616        let repr = Repr::zero();
617        assert_eq!(repr.as_sign_slice(), (Sign::Positive, &[][..]));
618
619        let repr = Repr::one();
620        assert_eq!(repr.as_slice(), &[1][..]);
621        assert_eq!(repr.as_sign_slice(), (Sign::Positive, &[1][..]));
622
623        let mut buffer = Buffer::allocate(1);
624        buffer.push(1);
625        let repr = Repr::from_buffer(buffer).with_sign(Sign::Negative);
626        assert_eq!(repr.as_sign_slice(), (Sign::Negative, &[1][..]));
627
628        let mut buffer = Buffer::allocate(2);
629        buffer.push(1);
630        buffer.push(2);
631        let repr = Repr::from_buffer(buffer);
632        assert_eq!(repr.as_slice(), &[1, 2][..]);
633        assert_eq!(repr.as_sign_slice(), (Sign::Positive, &[1, 2][..]));
634
635        let mut buffer = Buffer::allocate(2);
636        buffer.push(1);
637        buffer.push(2);
638        buffer.push(3);
639        buffer.push(4);
640        let repr = Repr::from_buffer(buffer);
641        assert_eq!(repr.as_slice(), &[1, 2, 3, 4][..]);
642        assert_eq!(repr.as_sign_slice(), (Sign::Positive, &[1, 2, 3, 4][..]));
643    }
644
645    #[test]
646    fn test_sign() {
647        let repr = Repr::zero();
648        assert_eq!(repr.sign(), Sign::Positive);
649        let repr = Repr::zero().neg();
650        assert_eq!(repr.sign(), Sign::Positive);
651
652        let repr = Repr::one();
653        assert_eq!(repr.sign(), Sign::Positive);
654        let repr = Repr::one().neg();
655        assert_eq!(repr.sign(), Sign::Negative);
656    }
657
658    #[test]
659    fn test_clone() {
660        // test Repr
661        let repr = Repr::from_word(123);
662        let repr2 = repr.clone();
663        assert_eq!(repr2.capacity(), 1);
664        assert_eq!(repr2.len(), 1);
665        assert_eq!(repr, repr2);
666
667        let repr = Repr::from_dword(123 << WORD_BITS_USIZE);
668        let repr2 = repr.clone();
669        assert_eq!(repr2.capacity(), repr.capacity());
670        assert_eq!(repr2.len(), repr.len());
671        assert_eq!(repr, repr2);
672
673        // test Buffer
674        let mut buffer = Buffer::allocate(100);
675        buffer.push(7);
676        buffer.push(8);
677        buffer.push(9);
678        let buffer2 = buffer.clone();
679        assert_eq!(buffer, buffer2);
680        assert_eq!(buffer2.capacity(), Buffer::default_capacity(3));
681
682        let repr = Repr::from_buffer(buffer);
683        let repr2 = repr.clone();
684        assert_eq!(repr.capacity(), Buffer::default_capacity(3));
685        assert_eq!(repr, repr2);
686    }
687
688    #[test]
689    fn test_convert_buffer() {
690        let buffer = Buffer::allocate(0);
691        let repr = Repr::from_buffer(buffer);
692        assert_eq!(repr.len(), 0);
693        assert!(repr.as_slice().is_empty());
694        let buffer_back = repr.into_buffer();
695        assert_eq!(buffer_back.len(), 0);
696        assert!(buffer_back.is_empty());
697
698        let mut buffer = Buffer::allocate(1);
699        buffer.push(123);
700        let repr = Repr::from_buffer(buffer);
701        assert_eq!(repr.len(), 1);
702        assert_eq!(repr.as_slice(), &[123][..]);
703        let buffer_back = repr.into_buffer();
704        assert_eq!(buffer_back.len(), 1);
705        assert_eq!(&buffer_back[..], &[123][..]);
706
707        let mut buffer = Buffer::allocate(2);
708        buffer.push(123);
709        buffer.push(456);
710        let repr = Repr::from_buffer(buffer);
711        assert_eq!(repr.len(), 2);
712        assert_eq!(repr.as_slice(), &[123, 456][..]);
713        let buffer_back = repr.into_buffer();
714        assert_eq!(buffer_back.len(), 2);
715        assert_eq!(&buffer_back[..], &[123, 456][..]);
716
717        let mut buffer = Buffer::allocate(3);
718        buffer.push(123);
719        buffer.push(456);
720        buffer.push(789);
721        let repr = Repr::from_buffer(buffer);
722        assert_eq!(repr.len(), 3);
723        assert_eq!(repr.as_slice(), &[123, 456, 789][..]);
724        let buffer_back = repr.into_buffer();
725        assert_eq!(buffer_back.len(), 3);
726        assert_eq!(&buffer_back[..], &[123, 456, 789][..]);
727    }
728
729    #[test]
730    fn test_clone_from() {
731        // test Repr
732        let repr = Repr::from_word(123);
733        let mut repr2 = Repr::zero();
734        repr2.clone_from(&repr);
735        assert_eq!(repr2.capacity(), repr.capacity());
736        assert_eq!(repr2.len(), repr.len());
737        assert_eq!(repr, repr2);
738
739        let repr = Repr::from_dword(123 << WORD_BITS_USIZE);
740        let mut repr2 = Repr::zero();
741        repr2.clone_from(&repr);
742        assert_eq!(repr2.capacity(), repr.capacity());
743        assert_eq!(repr2.len(), repr.len());
744        assert_eq!(repr, repr2);
745
746        // test Buffer
747        let mut buffer = Buffer::allocate(100);
748        buffer.push(7);
749        buffer.push(8);
750        buffer.push(9);
751        let mut buffer2 = Buffer::allocate(50);
752        buffer2.clone_from(&buffer);
753        assert_eq!(buffer, buffer2);
754        assert_ne!(buffer.capacity(), buffer2.capacity());
755
756        let repr = Repr::from_buffer(buffer);
757        let mut repr2 = Repr::from_buffer(buffer2);
758        repr2.clone_from(&repr);
759        assert_eq!(repr, repr2);
760    }
761
762    #[test]
763    fn test_resizing_clone_from() {
764        // test Buffer
765        let mut buf = Buffer::allocate(5);
766        assert_eq!(buf.capacity(), 7);
767
768        let mut buf2 = Buffer::allocate(4);
769        assert_eq!(buf2.capacity(), 6);
770        for i in 0..4 {
771            buf2.push(i);
772        }
773        buf.clone_from(&buf2);
774        assert_eq!(buf.capacity(), 7);
775        assert_eq!(&buf[..], [0, 1, 2, 3]);
776
777        let mut buf3 = Buffer::allocate(100);
778        for i in 0..100 {
779            buf3.push(i);
780        }
781        buf.clone_from(&buf3);
782        assert_eq!(buf.capacity(), Buffer::default_capacity(100));
783        assert_eq!(buf.len(), 100);
784
785        buf.clone_from(&buf2);
786        assert_eq!(buf.capacity(), 6);
787        assert_eq!(&buf[..], [0, 1, 2, 3]);
788
789        // test Repr
790        let mut repr = Repr::zero(); // start from inline
791        let repr2 = Repr::from_buffer(buf2);
792        repr.clone_from(&repr2);
793        assert_eq!(repr.len(), 4);
794        assert_eq!(repr, repr2);
795        assert!(matches!(repr.as_typed(), TypedReprRef::RefLarge(_)));
796
797        let repr3 = Repr::from_buffer(buf3);
798        repr.clone_from(&repr3);
799        assert_eq!(repr.len(), 100);
800        assert_eq!(repr, repr3);
801        assert!(matches!(repr.as_typed(), TypedReprRef::RefLarge(_)));
802
803        repr.clone_from(&repr2);
804        assert_eq!(repr.len(), 4);
805        assert_eq!(repr, repr2);
806        assert!(matches!(repr.as_typed(), TypedReprRef::RefLarge(_)));
807
808        let repr_inline = Repr::from_word(123);
809        repr.clone_from(&repr_inline);
810        assert_eq!(repr.len(), 1);
811        assert_eq!(repr, repr_inline);
812        assert!(matches!(repr.as_typed(), TypedReprRef::RefSmall(_)));
813    }
814}