qfall_math/
error.rs

1// Copyright © 2023 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//! Contains our central error enum for easy error propagation.
10//!
11//! This module contains this crate's error enum. This enum can hold all sorts
12//! of errors occurring in this crate s.t. error propagation is simple for
13//! developers of this crate and all sorts of thrown errors and error types can
14//! be easily found and accessed by developers using this crate. Furthermore,
15//! the actual errors are wrapped s.t. all information about the error can be
16//! unwrapped again.
17
18// **For developers:**
19// - How to add an error to an `enum`? First of all, find a name
20//   that is not too specific for your current case s.t. it could be used in other
21//   contexts afterwards as well. Then, find the spot according to your chosen error
22//   name in a alphanumerically sorted way in the list of supported errors in the doc
23//   comment and inside the `enum` itself.
24//   Afterwards, add the error to the list of implemented error
25//   types in the doc comment of the `enum` with a short description when it is thrown.
26//   Probably use this description for the doc comment above the implementation of
27//   error in the `enum`. Then, add `#[error(<error msg>)]` to define the error message
28//   output once your error is thrown. Below, write down `<error name>(<input>),` to
29//   define the error with its name and possibly some inputs. The input can be of the
30//   form [`String`], but also another error, whose conversion must be declared via
31//   `#[from] OtherError`. It is best to use the existing structure as a guide. For any
32//   further information, check out the here used [`thiserror`]-crate.
33
34use std::ffi::NulError;
35use thiserror::Error;
36
37/// [`MathError`] defines this crate's error enum, which can hold all sorts of
38/// errors occurring in this crate.
39///
40/// Implemented error types:
41/// - [`ConversionError`](MathError::ConversionError) is thrown if a conversion
42///   between types is not possible.
43/// - [`DivisionByZeroError`](MathError::DivisionByZeroError) is thrown if it is
44///   tried to perform a division by `0`.
45/// - [`InvalidExponent`](MathError::InvalidExponent) is thrown if an invalid
46///   exponent is used for a `pow` function.
47/// - [`InvalidIntegerInput`](MathError::InvalidIntegerInput) is thrown if an
48///   integer input is provided as parameter that does not meet the conditions
49///   of that function.
50/// - [`InvalidInterval`](MathError::InvalidInterval) is thrown if an invalid
51///   interval, e.g. of negative size, is provided.
52/// - [`InvalidModulus`](MathError::InvalidModulus) is thrown if an integer is
53///   provided, which is smaller than `2`.
54/// - [`NulError`](MathError::NulError) is thrown if a [`NulError`] is thrown,
55///   which currently only happens if an invalid string is given to construct
56///   a [`CString`](std::ffi::CString).
57/// - [`MismatchingMatrixDimension`](MathError::MismatchingMatrixDimension) is
58///   thrown if arithmetic is done with matrices of mismatching dimensions.
59/// - [`MismatchingModulus`](MathError::MismatchingModulus) is thrown if any
60///   function is called on two objects with different modulus where equal
61///   modulus is required.
62/// - [`NonPositive`](MathError::NonPositive) is thrown if the function expects
63///   a positive number, but a number smaller than `1` is provided.
64/// - [`NoSquareMatrix`](MathError::NoSquareMatrix) is thrown if a matrix is
65///   not square.
66/// - [`OutOfBounds`](MathError::OutOfBounds) is thrown if a provided index
67///   is not in a desired range.
68/// - [`VectorFunctionCalledOnNonVector`](MathError::VectorFunctionCalledOnNonVector)
69///   is thrown if a function defined on vectors was called on a matrix instance
70///   that is not a vector.
71///
72/// # Examples
73/// ```
74/// use qfall_math::{error::MathError, rational::Q};
75/// use std::str::FromStr;
76///
77/// fn parse_string_to_q() -> Result<(), MathError> {
78///     let text = "2/0";
79///     let q = Q::from_str(text)?;
80///     return Ok(());
81/// }
82/// ```
83#[derive(Error, Debug)]
84pub enum MathError {
85    /// Conversion error.
86    #[error("While performing the conversion an error occurred: {0}")]
87    ConversionError(String),
88
89    /// Division by zero error.
90    #[error("The division by zero is not possible {0}")]
91    DivisionByZeroError(String),
92
93    /// Invalid exponent.
94    #[error("Invalid exponent given: {0}")]
95    InvalidExponent(String),
96
97    /// Invalid integer was input to a specific function.
98    #[error("An invalid integer input was given as a parameter: {0}")]
99    InvalidIntegerInput(String),
100
101    /// Invalid interval provided.
102    #[error("An invalid interval was given: {0}")]
103    InvalidInterval(String),
104
105    /// Parse int to modulus error.
106    #[error("An invalid value should be parsed as a modulus {0}.")]
107    InvalidModulus(String),
108
109    /// Converts a [`NulError`], which currently only happens if an
110    /// invalid string is given to construct a [`CString`](std::ffi::CString).
111    #[error(
112        "A nul error occurred, which usually happens if an invalid \
113        string input is parsed to a CString {0}"
114    )]
115    NulError(#[from] NulError),
116
117    /// Mismatching matrix dimension error.
118    #[error("Mismatching matrix dimensions {0}")]
119    MismatchingMatrixDimension(String),
120
121    /// Mismatching modulus error.
122    #[error("Mismatching modulus.{0}")]
123    MismatchingModulus(String),
124
125    /// If an integer is not a positive number.
126    #[error(
127        "A function that can only be performed on positive values was \
128        performed on performed on a non-positive value, which is {0}."
129    )]
130    NonPositive(String),
131
132    /// If a matrix is not square.
133    #[error("The matrix is not square {0}")]
134    NoSquareMatrix(String),
135
136    /// If a provided index is out of bounds.
137    #[error(
138        "Invalid index submitted. The index is out of bounds.
139        The index has to {0}, and the provided value is {1}"
140    )]
141    OutOfBounds(String, String),
142
143    /// Some string to one of our data-types error occurred.
144    #[error("{0}")]
145    StringConversionError(#[from] StringConversionError),
146
147    /// If a function defined on vectors is called on a matrix that is not a vector.
148    #[error(
149        "Function named {0} is only defined for vectors and 
150        was called on a matrix of dimension {1}x{2}"
151    )]
152    VectorFunctionCalledOnNonVector(String, i64, i64),
153}
154
155/// [`StringConversionError`] defines an error enum,
156/// which holds all [`String`] to data-type conversion errors.
157///
158/// Implemented error types:
159/// - [`InvalidMatrix`](StringConversionError::InvalidMatrix) is thrown if an
160///   invalid string input of a matrix is given.
161/// - [`InvalidStringToPolyInput`](StringConversionError::InvalidStringToPolyInput)
162///   is thrown if an invalid string is given to construct a polynomial.
163/// - [`InvalidStringToPolyMissingWhitespace`](StringConversionError::InvalidStringToPolyMissingWhitespace)
164///   is thrown if an invalid string is given to construct a polynomial which
165///   did not contain two whitespaces.
166/// - [`InvalidStringToPolyModulusInput`](StringConversionError::InvalidStringToPolyModulusInput)
167///   is thrown if an invalid string is given
168///   to construct a [`PolyOverZq`](crate::integer_mod_q::PolyOverZq), i.e. it is
169///   not formatted correctly.
170/// - [`InvalidStringToPolyRingZqInput`](StringConversionError::InvalidStringToPolyRingZqInput)
171///   is thrown if an invalid string is given
172///   to construct a [`PolynomialRingZq`](crate::integer_mod_q::PolynomialRingZq), i.e. it is
173///   not formatted correctly.
174/// - [`InvalidStringToQInput`](StringConversionError::InvalidStringToQInput)
175///   is thrown if an invalid string is given to construct a [`Q`](crate::rational::Q).
176/// - [`InvalidStringToZInput`](StringConversionError::InvalidStringToZInput)
177///   is thrown if an invalid string is given to construct a [`Z`](crate::integer::Z).
178/// - [`InvalidStringToZqInput`](StringConversionError::InvalidStringToZqInput)
179///   is thrown if an invalid string is given to construct a [`Zq`](crate::integer_mod_q::Zq).
180///
181/// # Examples
182/// ```
183/// use qfall_math::error::StringConversionError;
184///
185/// fn throws_error() -> Result<(), StringConversionError> {
186///     return Err(
187///         StringConversionError::InvalidMatrix(String::from(
188///             "Some silly mistake was made",
189///         )),
190///     );
191///
192///     Ok(())
193/// }
194/// ```
195#[derive(Error, Debug)]
196pub enum StringConversionError {
197    /// Invalid Matrix input error.
198    #[error("invalid Matrix. {0}")]
199    InvalidMatrix(String),
200
201    /// Parse string to poly error.
202    #[error(
203        "Invalid string input to parse to polynomial {0}\nThe format must 
204        be '[#number of coefficients]  [0th coefficient] [1st coefficient] ...'. 
205        Note that the after the number of coefficients, there are two 
206        whitespace."
207    )]
208    InvalidStringToPolyInput(String),
209
210    /// Parse string to poly error with missing whitespace.
211    #[error(
212        "Invalid string input to parse to polynomial {0}
213        The string did not contain two whitespace at the start. Please note, 
214        that there have to two whitespace between number of coefficients 
215        and the first coefficient"
216    )]
217    InvalidStringToPolyMissingWhitespace(String),
218
219    /// Parse string to poly with modulus error.
220    #[error(
221        "Invalid string input to parse to polynomial mod q {0}.
222        The format must \
223        be '[#number of coefficients]  [0th coefficient] [1st coefficient] ... \
224        mod [modulus]'. 
225        Note that after the number of coefficients, there are two \
226        whitespaces."
227    )]
228    InvalidStringToPolyModulusInput(String),
229
230    /// Parse string to [`PolynomialRingZq`](crate::integer_mod_q::PolynomialRingZq) error.
231    #[error(
232        "Invalid string input to parse to polynomial / polynomial mod q {0}.
233        The format must \
234        be `[#number of coefficients of element]⌴⌴[0th coefficient]⌴ \
235        [1st coefficient]⌴...⌴/⌴[#number of coefficients of polynomial modulus] \
236        ⌴⌴[0th coefficient]⌴[1st coefficient]⌴...⌴mod⌴[q]`. 
237        Note that after the number of coefficients, there are two \
238        whitespaces."
239    )]
240    InvalidStringToPolyRingZqInput(String),
241
242    /// Parse string to [`Q`](crate::rational::Q) error
243    #[error("Invalid string input to parse to Q {0}")]
244    InvalidStringToQInput(String),
245
246    /// Parse string to [`Z`](crate::integer::Z) error.
247    #[error("Invalid string input to parse to Z {0}")]
248    InvalidStringToZInput(String),
249
250    /// Parse string to [`Zq`](crate::integer_mod_q::Zq) error.
251    #[error("Invalid string input to parse to Zq {0}")]
252    InvalidStringToZqInput(String),
253}