qfall_math/integer/z/
from.rs

1// Copyright © 2023 Sven Moog, Marcel Luca Schmidt
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! Implementations to create a [`Z`] value from other types.
10//!
11//! The explicit functions contain the documentation.
12
13use super::Z;
14use crate::{
15    error::{MathError, StringConversionError},
16    integer_mod_q::Modulus,
17    macros::for_others::implement_empty_trait_owned_ref,
18    traits::AsInteger,
19};
20use flint_sys::fmpz::{fmpz, fmpz_get_si, fmpz_get_ui, fmpz_init_set, fmpz_set_str, fmpz_setbit};
21use std::{ffi::CString, str::FromStr};
22
23impl Z {
24    /// Creates an Integer that can grow arbitrary large.
25    ///
26    /// Parameters:
27    /// - `value`: the initial value the integer should have
28    ///
29    /// Returns a new [`Z`] from the [`fmpz`] instance.
30    ///
31    /// # Safety
32    /// Since the parameter is a reference, it still has to be
33    /// properly cleared outside this function.
34    /// For example, by the drop trait of [`Z`].
35    ///
36    /// # Examples
37    /// ```compile_fail
38    /// use qfall_math::integer::Z;
39    ///
40    /// let z = Z::from(0);
41    ///
42    /// let a: Z = Z::from_fmpz_ref(&z.value);
43    /// ```
44    /// ```compile_fail
45    /// use qfall_math::integer::Z;
46    /// use flint_sys::fmpz::{fmpz, fmpz_clear};
47    ///
48    /// let value = fmpz(0);
49    ///
50    /// let a: Z = Z::from_fmpz_ref(&value);
51    ///
52    /// unsafe{fmpz_clear(&mut value)}
53    /// ```
54    pub(crate) fn from_fmpz_ref(value: &fmpz) -> Self {
55        let mut out = Z::default();
56        unsafe {
57            fmpz_init_set(&mut out.value, value);
58        }
59        out
60    }
61
62    /// Creates an Integer that can grow arbitrary large.
63    ///
64    /// Parameters:
65    /// - `value`: the initial value the integer should have
66    ///
67    /// Returns a new [`Z`] from the [`fmpz`] instance.
68    ///
69    /// # Safety
70    /// This function takes ownership. The caller has to ensure that the [`fmpz`]
71    /// is not dropped somewhere else. This means that calling this function
72    /// with an [`fmpz`] that is wrapped in a different data type is not allowed.
73    ///
74    /// # Examples
75    /// ```compile_fail
76    /// use qfall_math::integer::Z;
77    /// use flint_sys::fmpz::fmpz;
78    ///
79    /// let value = fmpz(0);
80    ///
81    /// let a: Z = Z::from_fmpz(value);
82    /// ```
83    #[allow(dead_code)]
84    pub(crate) unsafe fn from_fmpz(value: fmpz) -> Self {
85        Z { value }
86    }
87
88    /// Creates a [`Z`] integer from a [`String`]. This function takes a
89    /// base between `2` and `62` in which the number is represented.
90    ///
91    /// Parameters:
92    /// - `s`: the integer value as a string
93    /// - `base`: the base in which the integer is represented
94    ///
95    /// Returns a [`Z`] or an error if the provided string was not formatted
96    /// correctly, the provided string contains a `Null` byte or the base is out of bounds.
97    ///
98    /// # Examples
99    /// ```
100    /// use qfall_math::integer::Z;
101    ///  
102    /// let a: Z = Z::from_str_b("100", 2).unwrap();
103    /// assert_eq!(Z::from(4), a);
104    /// ```
105    ///
106    /// # Errors and Failures
107    /// - Returns a [`MathError`] of type [`OutOfBounds`](MathError::OutOfBounds) if the
108    ///   base is not between `2` and `62`.
109    /// - Returns a [`MathError`] of type
110    ///   [`StringConversionError`](MathError::StringConversionError)
111    ///     - if the provided string contains a `Null` byte, or
112    ///     - if the provided string was not formatted correctly.
113    pub fn from_str_b(s: &str, base: i32) -> Result<Self, MathError> {
114        if !(2..=62).contains(&base) {
115            return Err(MathError::OutOfBounds(
116                "between 2 and 62".to_owned(),
117                base.to_string(),
118            ));
119        }
120
121        if s.contains(char::is_whitespace) {
122            return Err(StringConversionError::InvalidStringToZInput(s.to_owned()))?;
123        }
124
125        // since |value| = |0| < 62 bits, we do not need to free the allocated space manually
126        let mut value: fmpz = fmpz(0);
127
128        let c_string = CString::new(s)?;
129
130        // -1 is returned if the string is an invalid input.
131        // Given the documentation `c_string.as_ptr()` is freed once c_string is deallocated
132        // 'The pointer will be valid for as long as `self` is'
133        // For reading more look at the documentation of `.as_ptr()`.
134        match unsafe { fmpz_set_str(&mut value, c_string.as_ptr(), base) } {
135            0 => Ok(Z { value }),
136            _ => Err(StringConversionError::InvalidStringToZInput(s.to_owned()))?,
137        }
138    }
139
140    /// Creates a [`Z`] integer from an iterable of [`u8`]s, i.e. a vector of bytes.
141    /// This function can only construct positive or zero integers, but not negative ones.
142    /// The inverse function to [`Z::from_bytes`] is [`Z::to_bytes`] for positive numbers including `0`.
143    ///
144    /// Parameters:
145    /// - `bytes`: specifies an iterable of bytes that should be set in the new [`Z`] instance.
146    ///   The first byte should be the least significant byte, i.e. its first bit the
147    ///   least significant bit.
148    ///
149    /// Returns a [`Z`] with the value provided by the byte iterable.
150    ///
151    /// # Examples
152    /// ```
153    /// use qfall_math::integer::Z;
154    /// // instantiate a byte-vector corresponding to "100000001"
155    /// // vec![0x01, 0x01] would also be sufficient
156    /// let bytes: Vec<u8> = vec![1, 1];
157    ///  
158    /// let a: Z = Z::from_bytes(&bytes);
159    /// assert_eq!(Z::from(257), a);
160    /// ```
161    pub fn from_bytes(bytes: &[u8]) -> Self {
162        let mut res = Z::ZERO;
163        for (i, byte) in bytes.iter().enumerate() {
164            for j in 0..u8::BITS {
165                // if j-th bit of `byte` is `1`, then set `i*8 + j`-th bit in fmpz to `1`
166                if ((byte >> j) & 1) % 2 == 1 {
167                    unsafe { fmpz_setbit(&mut res.value, (i as u32 * u8::BITS + j) as u64) };
168                }
169            }
170        }
171        res
172    }
173
174    /// Creates a [`Z`] integer from an iterable of [`bool`]s, i.e. a vector of bits.
175    /// This function can only construct positive or zero integers, but not negative ones.
176    ///
177    /// Parameters:
178    /// - `bits`: specifies an iterable of bits that should be set in the new [`Z`] instance.
179    ///   The first bit should be the least significant bit.
180    ///
181    /// Returns a [`Z`] with the value provided by the bit iterable.
182    ///
183    /// # Examples
184    /// ```
185    /// use qfall_math::integer::Z;
186    /// // instantiate a bit-vector corresponding to "101"
187    /// let bits: Vec<bool> = vec![true, false, true];
188    ///  
189    /// let a: Z = Z::from_bits(&bits);
190    /// assert_eq!(Z::from(5), a);
191    /// ```
192    pub fn from_bits(bits: &[bool]) -> Z {
193        let mut value = Z::default();
194        for (i, bit) in bits.iter().enumerate() {
195            if *bit {
196                unsafe { fmpz_setbit(&mut value.value, i as u64) };
197            }
198        }
199        value
200    }
201
202    /// Create a [`Z`] integer from a [`String`], i.e. its UTF8-Encoding.
203    /// This function can only construct positive or zero integers, but not negative ones.
204    /// The inverse of this function is [`Z::to_utf8`].
205    ///
206    /// Parameters:
207    /// - `message`: specifies the message that is transformed via its UTF8-Encoding
208    ///   to a new [`Z`] instance.
209    ///
210    /// Returns a [`Z`] with corresponding value to the message's UTF8-Encoding.
211    ///
212    /// # Examples
213    /// ```
214    /// use qfall_math::integer::Z;
215    /// let message = "hello!";
216    ///  
217    /// let value = Z::from_utf8(&message);
218    /// assert_eq!(Z::from(36762444129640u64), value);
219    /// ```
220    pub fn from_utf8(message: &str) -> Z {
221        Z::from_bytes(message.as_bytes())
222    }
223}
224
225/// A trait that indicates for which types the `From for Z` should be implemented.
226/// It is used as a workaround to implement the [`From`] trait without colliding
227/// with the default implementation for [`Z`] and also to filter out [`Zq`](crate::integer_mod_q::Zq).
228trait IntoZ {}
229impl IntoZ for &Z {}
230implement_empty_trait_owned_ref!(IntoZ for Modulus fmpz u8 u16 u32 u64 i8 i16 i32 i64);
231
232impl<Integer: AsInteger + IntoZ> From<Integer> for Z {
233    /// Converts an integer to [`Z`].
234    ///
235    /// Parameters:
236    /// `value`: must be a rust integer, [`Modulus`], or a reference of these types.
237    ///
238    /// Returns a [`Z`] with the value specified in the parameter.
239    ///
240    /// # Examples
241    /// ```
242    /// use qfall_math::integer::Z;
243    ///
244    /// let a = Z::from(10);
245    /// let b = Z::from(i64::MAX);
246    /// let c = Z::from(&u64::MAX);
247    /// ```
248    fn from(value: Integer) -> Self {
249        match value.get_fmpz_ref() {
250            Some(val) => Z::from_fmpz_ref(val),
251            None => unsafe {
252                let value = value.into_fmpz();
253                Z { value }
254            },
255        }
256    }
257}
258
259impl FromStr for Z {
260    type Err = MathError;
261
262    /// Creates a [`Z`] integer from a [`String`].
263    ///
264    /// Parameters:
265    /// - `s`: the integer value of form: `"12"` for the number 12 and `"-12"` for -12.
266    ///
267    /// Returns a [`Z`] or an error if the provided string was not formatted
268    /// correctly, or the provided string contains a `Null` byte.
269    ///
270    /// # Examples
271    /// ```
272    /// use std::str::FromStr;
273    /// use qfall_math::integer::Z;
274    ///  
275    /// let a: Z = "100".parse().unwrap();
276    /// let b: Z = Z::from(100);
277    /// ```
278    ///
279    /// # Errors and Failures
280    /// - Returns a [`MathError`] of type
281    ///   [`StringConversionError`](MathError::StringConversionError)
282    ///     - if the provided string contains a `Null` byte, or
283    ///     - if the provided string was not formatted correctly.
284    fn from_str(s: &str) -> Result<Self, Self::Err> {
285        Z::from_str_b(s, 10)
286    }
287}
288
289impl TryFrom<&Z> for i64 {
290    type Error = MathError;
291
292    /// Converts a [`Z`] into an [`i64`]. If the value is either too large
293    /// or too small an error is returned.
294    ///
295    /// Parameters:
296    /// - `value`: the value that will be converted into an [`i64`]
297    ///
298    /// Returns the value as an [`i64`] or an error if it does not fit
299    /// into an [`i64`].
300    ///
301    /// # Examples
302    /// ```
303    /// use qfall_math::integer::Z;
304    ///
305    /// let max = Z::from(i64::MAX);
306    /// assert_eq!(i64::MAX, i64::try_from(&max).unwrap());
307    ///
308    /// let max = Z::from(u64::MAX);
309    /// assert!(i64::try_from(&max).is_err());
310    /// ```
311    ///
312    /// # Errors and Failures
313    /// - Returns a [`MathError`] of type [`ConversionError`](MathError::ConversionError)
314    ///   if the value does not fit into an [`i64`]
315    fn try_from(value: &Z) -> Result<Self, Self::Error> {
316        // fmpz_get_si returns the i64::MAX or respectively i64::MIN
317        // if the value is too large/small to fit into an [`i64`].
318        // Hence we are required to manually check if the value is actually correct
319        let value_i64 = unsafe { fmpz_get_si(&value.value) };
320        if &value_i64 == value {
321            Ok(value_i64)
322        } else {
323            Err(MathError::ConversionError(format!(
324                "The provided value has to fit into an i64 and it doesn't as the 
325                provided value is {value}."
326            )))
327        }
328    }
329}
330
331impl TryFrom<Z> for i64 {
332    type Error = MathError;
333
334    /// Converts a [`Z`] into an [`i64`]. If the value is either too large
335    /// or too small an error is returned.
336    ///
337    /// Parameters:
338    /// - `value`: the value that will be converted into an [`i64`]
339    ///
340    /// Returns the value as an [`i64`] or an error if it does not fit
341    /// into an [`i64`]
342    ///
343    /// # Examples
344    /// ```
345    /// use qfall_math::integer::Z;
346    ///
347    /// let max = Z::from(i64::MAX);
348    /// assert_eq!(i64::MAX, i64::try_from(max).unwrap());
349    ///
350    /// let max = Z::from(u64::MAX) + 1;
351    /// assert!(i64::try_from(max).is_err());
352    /// ```
353    ///
354    /// # Errors and Failures
355    /// - Returns a [`MathError`] of type [`ConversionError`](MathError::ConversionError)
356    ///   if the value does not fit into an [`i64`]
357    fn try_from(value: Z) -> Result<Self, Self::Error> {
358        i64::try_from(&value)
359    }
360}
361
362impl TryFrom<&Z> for u64 {
363    type Error = MathError;
364
365    /// Converts a [`Z`] into an [`u64`]. If the value is either too large
366    /// or too small an error is returned.
367    ///
368    /// Parameters:
369    /// - `value`: the value that will be converted into an [`u64`]
370    ///
371    /// Returns the value as an [`u64`] or an error if it does not fit
372    /// into an [`u64`].
373    ///
374    /// # Examples
375    /// ```
376    /// use qfall_math::integer::Z;
377    ///
378    /// let max = Z::from(u64::MAX);
379    /// assert_eq!(u64::MAX, u64::try_from(&max).unwrap());
380    ///
381    /// let max = Z::from(u64::MAX) + 1;
382    /// assert!(u64::try_from(&max).is_err());
383    /// ```
384    ///
385    /// # Errors and Failures
386    /// - Returns a [`MathError`] of type [`ConversionError`](MathError::ConversionError)
387    ///   if the value does not fit into an [`u64`]
388    fn try_from(value: &Z) -> Result<Self, Self::Error> {
389        // The result is undefined if value.value does not fit into an ulong or is negative.
390        // Hence we are required to manually check if the value is actually correct
391        let value_u64 = unsafe { fmpz_get_ui(&value.value) };
392        if &value_u64 == value {
393            Ok(value_u64)
394        } else {
395            Err(MathError::ConversionError(format!(
396                "The provided value has to fit into an i64 and it doesn't as the 
397                provided value is {value}."
398            )))
399        }
400    }
401}
402
403impl TryFrom<Z> for u64 {
404    type Error = MathError;
405
406    /// Converts a [`Z`] into an [`u64`]. If the value is either too large
407    /// or too small an error is returned.
408    ///
409    /// Parameters:
410    /// - `value`: the value that will be converted into an [`u64`]
411    ///
412    /// Returns the value as an [`u64`] or an error if it does not fit
413    /// into an [`u64`].
414    ///
415    /// # Examples
416    /// ```
417    /// use qfall_math::integer::Z;
418    ///
419    /// let max = Z::from(u64::MAX);
420    /// assert_eq!(u64::MAX, u64::try_from(max).unwrap());
421    ///
422    /// let max = Z::from(u64::MAX) + 1;
423    /// assert!(u64::try_from(max).is_err());
424    /// ```
425    ///
426    /// # Errors and Failures
427    /// - Returns a [`MathError`] of type [`ConversionError`](MathError::ConversionError)
428    ///   if the value does not fit into an [`u64`]
429    fn try_from(value: Z) -> Result<Self, Self::Error> {
430        u64::try_from(&value)
431    }
432}
433
434impl From<&Vec<u8>> for Z {
435    /// Converts a byte vector of type [`u8`] to [`Z`] using [`Z::from_bytes`].
436    fn from(value: &Vec<u8>) -> Self {
437        Z::from_bytes(value)
438    }
439}
440
441impl From<Vec<u8>> for Z {
442    /// Converts a byte vector of type [`u8`] to [`Z`] using [`Z::from_bytes`].
443    fn from(value: Vec<u8>) -> Self {
444        Z::from_bytes(&value)
445    }
446}
447
448#[cfg(test)]
449mod test_from_bits {
450    use super::Z;
451
452    /// Checks whether small values are correctly instantiated by `from_bits`
453    /// and different byte representations are valid
454    #[test]
455    fn small_values() {
456        let vec_0 = vec![false];
457        let vec_1 = vec![false, false, false, true];
458        let vec_2 = vec![true, true, true, true, true];
459
460        let res_0 = Z::from_bits(&vec_0);
461        let res_1 = Z::from_bits(&vec_1);
462        let res_2 = Z::from_bits(&vec_2);
463
464        assert_eq!(Z::ZERO, res_0);
465        assert_eq!(Z::from(8), res_1);
466        assert_eq!(Z::from(31), res_2);
467    }
468
469    /// Checks whether large values are correctly instantiated by `from_bits`
470    /// and different byte representations are valid
471    #[test]
472    fn large_values() {
473        let vec = vec![true; 64];
474
475        let res = Z::from_bits(&vec);
476
477        assert_eq!(Z::from(u64::MAX), res);
478    }
479}
480
481#[cfg(test)]
482mod test_from_bytes {
483    use super::Z;
484
485    /// Checks whether small values are correctly instantiated by `from_bytes`
486    /// and different byte representations are valid
487    #[test]
488    fn small_values() {
489        let vec_0: Vec<u8> = vec![0];
490        let vec_1: Vec<u8> = vec![0x00, 0x01];
491        let vec_2: Vec<u8> = vec![1, 0];
492
493        let res_0 = Z::from_bytes(&vec_0);
494        let res_1 = Z::from_bytes(&vec_1);
495        let res_2 = Z::from_bytes(&vec_2);
496
497        assert_eq!(Z::ZERO, res_0);
498        assert_eq!(Z::from(256), res_1);
499        assert_eq!(Z::ONE, res_2);
500    }
501
502    /// Checks whether large values are correctly instantiated by `from_bytes`
503    /// and different byte representations are valid
504    #[test]
505    fn large_values() {
506        let vec_0: Vec<u8> = vec![255, 255, 255, 255, 255, 255, 255, 255];
507        let vec_1: Vec<u8> = vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
508
509        let res_0 = Z::from_bytes(&vec_0);
510        let res_1 = Z::from_bytes(&vec_1);
511
512        assert_eq!(Z::from(u64::MAX), res_0);
513        assert_eq!(Z::from(u64::MAX), res_1);
514    }
515
516    /// Checks for availability of `from_bytes` for array-inputs and the `from` trait
517    /// for vectors of borrowed and owned types
518    #[test]
519    fn availability() {
520        let arr: [u8; 2] = [0x01, 0x01];
521        let vec: Vec<u8> = vec![0x01, 0x01];
522
523        let res_0 = Z::from_bytes(&arr);
524        let res_1 = Z::from(&vec);
525        let res_2 = Z::from(vec);
526
527        assert_eq!(Z::from(257), res_0);
528        assert_eq!(Z::from(257), res_1);
529        assert_eq!(Z::from(257), res_2);
530    }
531}
532
533#[cfg(test)]
534/// Test the implementation of [`Z::from_utf8`] briefly.
535/// This module omits tests that were already provided for [`Z::from_bytes`].
536mod test_from_utf8 {
537    use super::Z;
538
539    /// Ensures that a wide range of (special) characters are correctly transformed.
540    #[test]
541    fn characters() {
542        let message = "flag{text#1234567890! a_zA-Z$€?/:;,.<>+*}";
543
544        let value = Z::from_utf8(message);
545
546        // easy trick s.t. we don't have to initialize a huge [`Z`] value
547        // while this test should still fail if the value changes
548        let value_zq = value % 65537;
549
550        assert_eq!(Z::from(58285), value_zq);
551    }
552
553    /// Ensure that the empty string results in a zero value.
554    #[test]
555    fn empty_string() {
556        let message = "";
557
558        let value = Z::from_utf8(message);
559
560        assert_eq!(Z::ZERO, value);
561    }
562}
563
564#[cfg(test)]
565/// Test the different implementations for types that implement [`AsInteger`] and [`IntoZ`]
566mod tests_from_int {
567    use super::*;
568    use crate::integer_mod_q::Modulus;
569
570    /// Ensure that the [`From`] trait is available for singed and unsigned integers
571    /// of 8, 16, 32, and 64 bit length and for their owned and borrowed variants.
572    /// Tested with their maximum value.
573    #[test]
574    fn rust_int_max() {
575        // signed
576        let _ = Z::from(i8::MAX);
577        let _ = Z::from(i16::MAX);
578        let _ = Z::from(i32::MAX);
579        let _ = Z::from(i64::MAX);
580        let _ = Z::from(&i8::MAX);
581        let _ = Z::from(&i16::MAX);
582        let _ = Z::from(&i32::MAX);
583        let _ = Z::from(&i64::MAX);
584
585        // unsigned
586        let _ = Z::from(u8::MAX);
587        let _ = Z::from(u16::MAX);
588        let _ = Z::from(u32::MAX);
589        let _ = Z::from(u64::MAX);
590        let _ = Z::from(&u8::MAX);
591        let _ = Z::from(&u16::MAX);
592        let _ = Z::from(&u32::MAX);
593        let _ = Z::from(&u64::MAX);
594    }
595
596    /// Ensure that the [`From`] trait is available for singed and unsigned integers
597    /// of 8, 16, 32, and 64 bit length and for their owned and borrowed variants.
598    /// Tested with their minimum value.
599    #[test]
600    fn rust_int_min() {
601        // signed
602        let _ = Z::from(i8::MIN);
603        let _ = Z::from(i16::MIN);
604        let _ = Z::from(i32::MIN);
605        let _ = Z::from(i64::MIN);
606        let _ = Z::from(&i8::MIN);
607        let _ = Z::from(&i16::MIN);
608        let _ = Z::from(&i32::MIN);
609        let _ = Z::from(&i64::MIN);
610
611        // unsigned
612        let _ = Z::from(u8::MIN);
613        let _ = Z::from(u16::MIN);
614        let _ = Z::from(u32::MIN);
615        let _ = Z::from(u64::MIN);
616        let _ = Z::from(&u8::MIN);
617        let _ = Z::from(&u16::MIN);
618        let _ = Z::from(&u32::MIN);
619        let _ = Z::from(&u64::MIN);
620    }
621
622    /// Ensure that the [`From`] trait is available for small and large,
623    /// borrowed and owned [`Modulus`] instances.
624    #[test]
625    fn modulus() {
626        let val_1 = Z::from(u64::MAX);
627        let mod_1 = Modulus::from(&val_1);
628        let val_2 = Z::from(10);
629        let mod_2 = Modulus::from(&val_2);
630
631        assert_eq!(val_1, Z::from(&mod_1));
632        assert_eq!(val_2, Z::from(&mod_2));
633
634        assert_eq!(val_1, Z::from(mod_1));
635        assert_eq!(val_2, Z::from(mod_2));
636    }
637
638    /// Ensure that the [`From`] trait is available for small and large,
639    /// borrowed and owned [`Z`] instances.
640    #[test]
641    fn z() {
642        let original_large = Z::from(u64::MAX);
643        let original_small = Z::ONE;
644
645        assert_eq!(original_large, Z::from(&original_large));
646        assert_eq!(original_large, original_large.clone());
647
648        assert_eq!(original_small, Z::from(&original_small));
649        assert_eq!(original_small, Z::ONE);
650    }
651
652    /// Ensure that the [`From`] trait is available for small and large,
653    /// borrowed and owned [`fmpz`] instances.
654    #[test]
655    fn fmpz() {
656        let large_z = Z::from(u64::MAX);
657        let small_z = Z::ONE;
658
659        assert_eq!(large_z, Z::from(&large_z.value));
660        assert_eq!(large_z, Z::from(large_z.value));
661
662        assert_eq!(small_z, Z::from(&small_z.value));
663        assert_eq!(small_z, Z::from(small_z.value));
664    }
665}
666
667#[cfg(test)]
668mod tests_from_str {
669    use crate::integer::Z;
670    use std::str::FromStr;
671
672    /// Ensure that initialization with large numbers works.
673    #[test]
674    fn max_int_positive() {
675        assert!(Z::from_str(&(i64::MAX).to_string()).is_ok());
676    }
677
678    /// Ensure that initialization with large numbers (larger than i64) works.
679    #[test]
680    fn large_positive() {
681        assert!(Z::from_str(&"1".repeat(65)).is_ok());
682    }
683
684    /// Ensure that initialization with large negative numbers works.
685    #[test]
686    fn max_int_negative() {
687        assert!(Z::from_str(&(i64::MIN).to_string()).is_ok());
688    }
689
690    /// Ensure that initialization with large negative numbers (larger than i64) works.
691    #[test]
692    fn large_negative() {
693        let mut s = "-".to_string();
694        s.push_str(&"1".repeat(65));
695
696        assert!(Z::from_str(&s).is_ok());
697    }
698
699    /// Ensure that wrong initialization yields an Error.
700    #[test]
701    fn error_wrong_letters() {
702        assert!(Z::from_str("hbrkt35itu3gg").is_err());
703    }
704
705    /// Ensure that wrong initialization yields an Error.
706    #[test]
707    fn error_wrong_order() {
708        assert!(Z::from_str("3-2").is_err());
709    }
710
711    /// Ensure that wrong initialization yields an Error.
712    #[test]
713    fn error_rational() {
714        assert!(Z::from_str("876/543").is_err());
715    }
716
717    /// Ensure that wrong initialization yields an Error.
718    #[test]
719    fn whitespace_mid() {
720        assert!(Z::from_str("876 543").is_err());
721    }
722
723    /// Ensure that wrong initialization yields an Error.
724    #[test]
725    fn whitespace_start() {
726        assert!(Z::from_str(" 876543").is_err());
727    }
728
729    /// Ensure that wrong initialization yields an Error.
730    #[test]
731    fn whitespace_end() {
732        assert!(Z::from_str("876543 ").is_err());
733    }
734
735    /// Ensure that wrong initialization yields an Error.
736    #[test]
737    fn whitespace_minus() {
738        assert!(Z::from_str("- 876543").is_err());
739    }
740}
741
742#[cfg(test)]
743mod test_from_str_b {
744    use crate::integer::Z;
745
746    /// ensure that an error is returned, if an invalid base is provided
747    #[test]
748    fn out_of_bounds() {
749        let value = "100010";
750
751        assert!(Z::from_str_b(value, -1).is_err());
752        assert!(Z::from_str_b(value, 0).is_err());
753        assert!(Z::from_str_b(value, 1).is_err());
754        assert!(Z::from_str_b(value, 63).is_err());
755    }
756
757    /// ensure that from_str works with a binary-string
758    #[test]
759    fn from_str_binary() {
760        assert_eq!(Z::from(20), Z::from_str_b("10100", 2).unwrap());
761        assert_eq!(Z::from(-20), Z::from_str_b("-10100", 2).unwrap());
762    }
763
764    /// ensure that from_str works with a hex-string
765    #[test]
766    fn from_str_hex() {
767        assert_eq!(Z::from(160), Z::from_str_b("a0", 16).unwrap());
768        assert_eq!(Z::from(-170), Z::from_str_b("-aa", 16).unwrap());
769    }
770}
771
772#[cfg(test)]
773mod test_from_fmpz {
774    use super::Z;
775    use flint_sys::fmpz::{fmpz, fmpz_set_ui};
776
777    /// Ensure that `from_fmpz` is available for small and large numbers
778    #[test]
779    fn small_numbers() {
780        let fmpz_1 = fmpz(0);
781        let fmpz_2 = fmpz(100);
782
783        assert_eq!(unsafe { Z::from_fmpz(fmpz_1) }, Z::ZERO);
784        assert_eq!(unsafe { Z::from_fmpz(fmpz_2) }, Z::from(100));
785    }
786
787    /// Ensure that `from_fmpz` is available for small and large numbers
788    #[test]
789    fn large_numbers() {
790        let mut fmpz_1 = fmpz(0);
791        unsafe { fmpz_set_ui(&mut fmpz_1, u64::MAX) }
792
793        assert_eq!(unsafe { Z::from_fmpz(fmpz_1) }, Z::from(u64::MAX));
794    }
795}
796
797#[cfg(test)]
798mod test_from_fmpz_ref {
799    use super::Z;
800
801    /// Ensure that `from_fmpz` is available for small and large numbers
802    #[test]
803    fn large_small_numbers() {
804        let mod_1 = Z::from(u64::MAX);
805        let mod_2 = Z::ZERO;
806
807        let _ = Z::from_fmpz_ref(&mod_1.value);
808        let _ = Z::from_fmpz_ref(&mod_2.value);
809    }
810}
811
812#[cfg(test)]
813mod test_try_from_into_i64 {
814    use crate::integer::Z;
815
816    /// ensure that an error is returned, if the value of the [`Z`]
817    /// does not fit into an [`i64`]
818    #[test]
819    fn overflow() {
820        assert!(i64::try_from(&Z::from(u64::MAX)).is_err());
821        assert!(i64::try_from(&(-1 * Z::from(u64::MAX))).is_err());
822        assert!(i64::try_from(Z::from(u64::MAX)).is_err());
823        assert!(i64::try_from(-1 * Z::from(u64::MAX)).is_err());
824    }
825
826    /// ensure that a correct value is returned for values in bounds.
827    #[test]
828    fn correct() {
829        let min = Z::from(i64::MIN);
830        let max = Z::from(i64::MAX);
831        let z_42 = Z::from(42);
832
833        assert_eq!(i64::MIN, i64::try_from(&min).unwrap());
834        assert_eq!(i64::MAX, i64::try_from(&max).unwrap());
835        assert_eq!(0, i64::try_from(&Z::ZERO).unwrap());
836        assert_eq!(42, i64::try_from(&z_42).unwrap());
837
838        assert_eq!(i64::MIN, i64::try_from(min).unwrap());
839        assert_eq!(i64::MAX, i64::try_from(max).unwrap());
840        assert_eq!(0, i64::try_from(Z::ZERO).unwrap());
841        assert_eq!(42, i64::try_from(z_42).unwrap());
842    }
843}
844
845#[cfg(test)]
846mod test_try_from_into_u64 {
847    use crate::integer::Z;
848
849    /// ensure that an error is returned, if the value of the [`Z`]
850    /// does not fit into an [`u64`]
851    #[test]
852    fn overflow() {
853        assert!(u64::try_from(&(Z::from(u64::MAX) + 1)).is_err());
854        assert!(u64::try_from(&Z::MINUS_ONE).is_err());
855    }
856
857    /// ensure that a correct value is returned for values in bounds.
858    #[test]
859    fn correct() {
860        let min = Z::from(0);
861        let max = Z::from(u64::MAX);
862        let z_42 = Z::from(42);
863
864        assert_eq!(0, u64::try_from(&min).unwrap());
865        assert_eq!(u64::MAX, u64::try_from(&max).unwrap());
866        assert_eq!(0, i64::try_from(&Z::ZERO).unwrap());
867        assert_eq!(42, i64::try_from(&z_42).unwrap());
868
869        assert_eq!(0, u64::try_from(min).unwrap());
870        assert_eq!(u64::MAX, u64::try_from(max).unwrap());
871        assert_eq!(0, u64::try_from(Z::ZERO).unwrap());
872        assert_eq!(42, u64::try_from(z_42).unwrap());
873    }
874}