qfall_math/integer_mod_q/modulus/to_string.rs
1// Copyright © 2023 Marcel Luca Schmidt, Marvin Beckmann
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//! This module contains all options to convert a modulus of type
10//! [`Modulus`] into a [`String`].
11//!
12//! This includes the [`Display`](std::fmt::Display) trait.
13
14use super::Modulus;
15use crate::macros::for_others::implement_for_owned;
16use core::fmt;
17use flint_sys::fmpz::fmpz_get_str;
18use std::{ffi::CStr, ptr::null_mut};
19
20impl From<&Modulus> for String {
21 /// Converts a [`Modulus`] into its [`String`] representation.
22 ///
23 /// Parameters:
24 /// - `value`: specifies the modulus that will be represented as a [`String`]
25 ///
26 /// Returns a [`String`].
27 ///
28 /// # Examples
29 /// ```
30 /// use qfall_math::integer_mod_q::Modulus;
31 /// use std::str::FromStr;
32 /// let modulus = Modulus::from_str("6").unwrap();
33 ///
34 /// let string: String = modulus.into();
35 /// ```
36 fn from(value: &Modulus) -> Self {
37 value.to_string()
38 }
39}
40
41implement_for_owned!(Modulus, String, From);
42
43impl fmt::Display for Modulus {
44 /// Allows to convert a modulus of type [`Modulus`] into a [`String`].
45 ///
46 /// # Examples
47 /// ```
48 /// use qfall_math::integer_mod_q::Modulus;
49 /// use std::str::FromStr;
50 /// use core::fmt;
51 ///
52 /// let modulus = Modulus::from(42);
53 /// println!("{modulus}");
54 /// ```
55 ///
56 /// ```
57 /// use qfall_math::integer_mod_q::Modulus;
58 /// use std::str::FromStr;
59 ///
60 /// let modulus = Modulus::from(42);
61 /// let modulus_string = modulus.to_string();
62 /// ```
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 // we have to access modulus.n[0] manually because there is no dedicated
65 // method in FLINT
66 let c_str_ptr = unsafe { fmpz_get_str(null_mut(), 10, &self.modulus.n[0]) };
67
68 // we expect c_str_ptr to be reference a real value, hence get_str returns an
69 // actual value, hence a simple unwrap should be sufficient and we do not have
70 // to consider an exception
71 //
72 // c_string should not be null either, since we call this method on an
73 // instantiated object
74 let msg = "We expect the pointer to point to a real value and the c_string
75 not to be null. This error occurs if the provided string does not have UTF-8 format.";
76 let return_str = unsafe { CStr::from_ptr(c_str_ptr).to_str().expect(msg).to_owned() };
77
78 unsafe { libc::free(c_str_ptr as *mut libc::c_void) };
79
80 write!(f, "{return_str}")
81 }
82}
83
84#[cfg(test)]
85mod test_to_string {
86 use crate::integer_mod_q::Modulus;
87 use std::str::FromStr;
88
89 /// Tests whether a large modulus works in a roundtrip
90 #[test]
91 fn working_large() {
92 let cmp_str = "1".repeat(65);
93 let cmp = Modulus::from_str(&cmp_str).unwrap();
94
95 assert_eq!(cmp_str, cmp.to_string());
96 }
97
98 /// Tests whether a positive modulus works in a roundtrip
99 #[test]
100 fn working_positive() {
101 let cmp_str = "42";
102 let cmp = Modulus::from_str(cmp_str).unwrap();
103
104 assert_eq!(cmp_str, cmp.to_string());
105 }
106
107 /// Tests whether a modulus that is created using a string, returns a
108 /// string that can be used to create a [`Modulus`]
109 #[test]
110 fn working_use_result_of_to_string_as_input() {
111 let cmp_str = "42";
112 let cmp = Modulus::from_str(cmp_str).unwrap();
113
114 let cmp_str_2 = cmp.to_string();
115
116 assert!(Modulus::from_str(&cmp_str_2).is_ok());
117 }
118
119 /// Ensures that the `Into<String>` trait works properly
120 #[test]
121 fn into_works_properly() {
122 let cmp = "6";
123 let modulus = Modulus::from_str(cmp).unwrap();
124
125 let string: String = modulus.clone().into();
126 let borrowed_string: String = (&modulus).into();
127
128 assert_eq!(cmp, string);
129 assert_eq!(cmp, borrowed_string);
130 }
131}