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}