qfall_math/integer_mod_q/z_q/
to_string.rs

1// Copyright © 2023 Marcel Luca Schmidt, Niklas Siemer
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 an integer of type
10//! [`Zq`] into a [`String`].
11//!
12//! This includes the [`Display`](std::fmt::Display) trait.
13
14use super::Zq;
15use crate::macros::for_others::implement_for_owned;
16use core::fmt;
17use std::string::FromUtf8Error;
18
19impl From<&Zq> for String {
20    /// Converts a [`Zq`] into its [`String`] representation.
21    ///
22    /// Parameters:
23    /// - `value`: specifies the integer and modulus that will be represented as a [`String`]
24    ///
25    /// Returns a [`String`] of the form `"x mod q"`.
26    ///
27    /// # Examples
28    /// ```
29    /// use qfall_math::integer_mod_q::Zq;
30    /// use std::str::FromStr;
31    /// let zq = Zq::from_str("3 mod 5").unwrap();
32    ///
33    /// let string: String = zq.into();
34    /// ```
35    fn from(value: &Zq) -> Self {
36        value.to_string()
37    }
38}
39
40implement_for_owned!(Zq, String, From);
41
42impl fmt::Display for Zq {
43    /// Allows to convert an integer of type [`Zq`] into a [`String`].
44    ///
45    /// Returns the integer in form of a [`String`]. For integer `2 mod 4`
46    /// the String looks like this `2 mod 4`.
47    ///
48    /// # Examples
49    /// ```
50    /// use qfall_math::integer_mod_q::Zq;
51    /// use std::str::FromStr;
52    /// use core::fmt;
53    ///
54    /// let integer_mod_q = Zq::from((42, 3));
55    /// println!("{integer_mod_q}");
56    /// ```
57    ///
58    /// ```
59    /// use qfall_math::integer_mod_q::Zq;
60    /// use std::str::FromStr;
61    /// use core::fmt;
62    ///
63    /// let integer_mod_q = Zq::from((42, 3));
64    /// let integer_string = integer_mod_q.to_string();
65    /// ```
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(f, "{} mod {}", self.value, self.modulus)
68    }
69}
70
71impl Zq {
72    /// Enables conversion to a UTF8-Encoded [`String`] for [`Zq`] values.
73    /// The inverse to this function is [`Zq::from_utf8`] for valid UTF8-Encodings.
74    ///
75    /// **Warning**: Not every byte-sequence forms a valid UTF8-character.
76    /// If this is the case, a [`FromUtf8Error`] will be returned.
77    ///
78    /// Returns the corresponding UTF8-encoded [`String`] or a
79    /// [`FromUtf8Error`] if the byte sequence contains an invalid UTF8-character.
80    ///
81    /// # Examples
82    /// ```
83    /// use qfall_math::integer_mod_q::Zq;
84    /// let value = Zq::from((10, 63));
85    ///
86    /// let text: String = value.to_utf8().unwrap();
87    /// ```
88    ///
89    /// # Errors and Failures
90    /// - Returns a [`FromUtf8Error`] if the integer's byte sequence contains
91    ///   valid UTF8-characters.
92    pub fn to_utf8(&self) -> Result<String, FromUtf8Error> {
93        String::from_utf8(
94            self.get_representative_least_nonnegative_residue()
95                .to_bytes(),
96        )
97    }
98}
99
100#[cfg(test)]
101mod test_to_string {
102    use crate::integer_mod_q::Zq;
103    use std::str::FromStr;
104
105    /// Tests whether a large integer works in a roundtrip
106    #[test]
107    fn working_large_positive() {
108        let cmp = Zq::from_str(&format!("{} mod {}", u64::MAX, u128::MAX)).unwrap();
109
110        assert_eq!(format!("{} mod {}", u64::MAX, u128::MAX), cmp.to_string());
111    }
112
113    /// Tests whether a large integer works in a roundtrip
114    #[test]
115    fn working_large_negative() {
116        let cmp = Zq::from_str(&format!("-{} mod {}", u64::MAX, u128::MAX)).unwrap();
117        let diff = u128::MAX - u64::MAX as u128;
118
119        assert_eq!(format!("{diff} mod {}", u128::MAX), cmp.to_string());
120    }
121
122    /// Tests whether a positive integer works in a roundtrip
123    #[test]
124    fn working_positive() {
125        let cmp = Zq::from_str("42 mod 60").unwrap();
126
127        assert_eq!("42 mod 60", cmp.to_string());
128    }
129
130    /// Tests whether a negative integer works in a roundtrip
131    #[test]
132    fn working_negative() {
133        let cmp = Zq::from_str("-40 mod 3").unwrap();
134
135        assert_eq!("2 mod 3", cmp.to_string());
136    }
137
138    /// Tests whether a integer that is created using a string, returns a
139    /// string that can be used to create a [`Zq`]
140    #[test]
141    fn working_use_result_of_to_string_as_input() {
142        let cmp = Zq::from((42, 10));
143
144        let cmp_str = cmp.to_string();
145
146        assert!(Zq::from_str(&cmp_str).is_ok());
147    }
148
149    /// Ensures that the `Into<String>` trait works properly
150    #[test]
151    fn into_works_properly() {
152        let cmp = "6 mod 11";
153        let zq = Zq::from_str(cmp).unwrap();
154
155        let string: String = zq.clone().into();
156        let borrowed_string: String = (&zq).into();
157
158        assert_eq!(cmp, string);
159        assert_eq!(cmp, borrowed_string);
160    }
161}
162
163#[cfg(test)]
164/// This module omits tests performed in [`crate::integer::Z::to_utf8`].
165mod test_to_utf8 {
166    use super::Zq;
167
168    /// Ensures that [`Zq::to_utf8`] is inverse to [`Zq::from_utf8`] for valid UTF8-Encodings.
169    #[test]
170    fn inverse_to_from_utf8() {
171        let cmp_text = "Test!";
172
173        let value = Zq::from_utf8(cmp_text, u64::MAX).unwrap();
174        let text = value.to_utf8().unwrap();
175
176        assert_eq!(cmp_text, text);
177    }
178}