Skip to main content

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