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}