diff --git a/src/integer/mat_poly_over_z/unsafe_functions.rs b/src/integer/mat_poly_over_z/unsafe_functions.rs index 77a97d7b7..03502271b 100644 --- a/src/integer/mat_poly_over_z/unsafe_functions.rs +++ b/src/integer/mat_poly_over_z/unsafe_functions.rs @@ -10,10 +10,16 @@ //! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe. use super::MatPolyOverZ; -use crate::macros::unsafe_passthrough::unsafe_getter; -use flint_sys::fmpz_poly_mat::fmpz_poly_mat_struct; +use crate::macros::unsafe_passthrough::{unsafe_getter, unsafe_setter}; +use flint_sys::fmpz_poly_mat::{fmpz_poly_mat_clear, fmpz_poly_mat_struct}; unsafe_getter!(MatPolyOverZ, matrix, fmpz_poly_mat_struct); +unsafe_setter!( + MatPolyOverZ, + matrix, + fmpz_poly_mat_struct, + fmpz_poly_mat_clear +); #[cfg(test)] mod test_get_fmpz_poly_mat_struct { @@ -40,3 +46,29 @@ mod test_get_fmpz_poly_mat_struct { assert_eq!(poly, mat.get_entry(0, 0).unwrap()); } } + +#[cfg(test)] +mod test_set_fmpz_poly_mat_struct { + use super::MatPolyOverZ; + use crate::{integer::PolyOverZ, traits::MatrixGetEntry}; + use flint_sys::fmpz_poly_mat::fmpz_poly_mat_init; + use std::{mem::MaybeUninit, str::FromStr}; + + /// Checks availability of the setter for [`MatPolyOverZ::matrix`] + /// and its ability to modify [`MatPolyOverZ`]. + #[test] + #[allow(unused_mut)] + fn availability_and_modification() { + let mut mat = MatPolyOverZ::from_str("[[1 1]]").unwrap(); + let mut flint_struct = MaybeUninit::uninit(); + let flint_struct = unsafe { + fmpz_poly_mat_init(flint_struct.as_mut_ptr(), 1, 1); + flint_struct.assume_init() + }; + let poly = PolyOverZ::default(); + + unsafe { mat.set_fmpz_poly_mat_struct(flint_struct) }; + + assert_eq!(poly, mat.get_entry(0, 0).unwrap()); + } +} diff --git a/src/integer/mat_z/unsafe_functions.rs b/src/integer/mat_z/unsafe_functions.rs index ee624f097..c70fd04c7 100644 --- a/src/integer/mat_z/unsafe_functions.rs +++ b/src/integer/mat_z/unsafe_functions.rs @@ -10,10 +10,11 @@ //! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe. use super::MatZ; -use crate::macros::unsafe_passthrough::unsafe_getter; -use flint_sys::fmpz_mat::fmpz_mat_struct; +use crate::macros::unsafe_passthrough::{unsafe_getter, unsafe_setter}; +use flint_sys::fmpz_mat::{fmpz_mat_clear, fmpz_mat_struct}; unsafe_getter!(MatZ, matrix, fmpz_mat_struct); +unsafe_setter!(MatZ, matrix, fmpz_mat_struct, fmpz_mat_clear); #[cfg(test)] mod test_get_fmpz_mat_struct { @@ -42,3 +43,28 @@ mod test_get_fmpz_mat_struct { assert_eq!(Z::from(2), mat.get_entry(0, 0).unwrap()); } } + +#[cfg(test)] +mod test_set_fmpz_mat_struct { + use super::MatZ; + use crate::{integer::Z, traits::MatrixGetEntry}; + use flint_sys::fmpz_mat::fmpz_mat_init; + use std::{mem::MaybeUninit, str::FromStr}; + + /// Checks availability of the setter for [`MatZ::matrix`] + /// and its ability to modify [`MatZ`]. + #[test] + #[allow(unused_mut)] + fn availability_and_modification() { + let mut mat = MatZ::from_str("[[1]]").unwrap(); + let mut flint_struct = MaybeUninit::uninit(); + let flint_struct = unsafe { + fmpz_mat_init(flint_struct.as_mut_ptr(), 1, 1); + flint_struct.assume_init() + }; + + unsafe { mat.set_fmpz_mat_struct(flint_struct) }; + + assert_eq!(Z::from(0), mat.get_entry(0, 0).unwrap()); + } +} diff --git a/src/integer/poly_over_z/unsafe_functions.rs b/src/integer/poly_over_z/unsafe_functions.rs index c16731f91..641c8ef93 100644 --- a/src/integer/poly_over_z/unsafe_functions.rs +++ b/src/integer/poly_over_z/unsafe_functions.rs @@ -10,10 +10,11 @@ //! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe. use super::PolyOverZ; -use crate::macros::unsafe_passthrough::unsafe_getter; -use flint_sys::fmpz_poly::fmpz_poly_struct; +use crate::macros::unsafe_passthrough::{unsafe_getter, unsafe_setter}; +use flint_sys::fmpz_poly::{fmpz_poly_clear, fmpz_poly_struct}; unsafe_getter!(PolyOverZ, poly, fmpz_poly_struct); +unsafe_setter!(PolyOverZ, poly, fmpz_poly_struct, fmpz_poly_clear); #[cfg(test)] mod test_get_fmpz_poly_struct { @@ -34,3 +35,27 @@ mod test_get_fmpz_poly_struct { assert_eq!(PolyOverZ::from(2), poly); } } + +#[cfg(test)] +mod test_set_fmpz_poly_struct { + use super::PolyOverZ; + use flint_sys::fmpz_poly::fmpz_poly_init; + use std::mem::MaybeUninit; + + /// Checks availability of the setter for [`PolyOverZ::poly`] + /// and its ability to modify [`PolyOverZ`]. + #[test] + #[allow(unused_mut)] + fn availability_and_modification() { + let mut poly = PolyOverZ::from(1); + let mut flint_struct = MaybeUninit::uninit(); + let flint_struct = unsafe { + fmpz_poly_init(flint_struct.as_mut_ptr()); + flint_struct.assume_init() + }; + + unsafe { poly.set_fmpz_poly_struct(flint_struct) }; + + assert_eq!(PolyOverZ::default(), poly); + } +} diff --git a/src/integer/z/unsafe_functions.rs b/src/integer/z/unsafe_functions.rs index 07c1c54ed..934dac0cd 100644 --- a/src/integer/z/unsafe_functions.rs +++ b/src/integer/z/unsafe_functions.rs @@ -9,16 +9,20 @@ //! This module contains public functions that enable access to underlying //! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe. -use crate::{integer::Z, macros::unsafe_passthrough::unsafe_getter}; -use flint_sys::fmpz::fmpz; +use crate::{ + integer::Z, + macros::unsafe_passthrough::{unsafe_getter, unsafe_setter}, +}; +use flint_sys::fmpz::{fmpz, fmpz_clear}; unsafe_getter!(Z, value, fmpz); +unsafe_setter!(Z, value, fmpz, fmpz_clear); #[cfg(test)] mod test_get_fmpz { use super::Z; - /// Checks availability of the getter for [`Z::value`] + /// Checks availability of the setter for [`Z::value`] /// and its ability to be modified. #[test] #[allow(unused_mut)] @@ -32,3 +36,22 @@ mod test_get_fmpz { assert_eq!(Z::from(2), integer); } } + +#[cfg(test)] +mod test_set_fmpz { + use super::Z; + use flint_sys::fmpz::fmpz; + + /// Checks availability of the setter for [`Z::value`] + /// and its ability to modify [`Z`]. + #[test] + #[allow(unused_mut)] + fn availability_and_modification() { + let mut integer = Z::from(1); + let b = fmpz(2); + + unsafe { integer.set_fmpz(b) }; + + assert_eq!(Z::from(2), integer); + } +} diff --git a/src/integer_mod_q/mat_polynomial_ring_zq/unsafe_functions.rs b/src/integer_mod_q/mat_polynomial_ring_zq/unsafe_functions.rs index 2dfd017ca..dc5dd1138 100644 --- a/src/integer_mod_q/mat_polynomial_ring_zq/unsafe_functions.rs +++ b/src/integer_mod_q/mat_polynomial_ring_zq/unsafe_functions.rs @@ -10,7 +10,7 @@ //! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe. use super::MatPolynomialRingZq; -use crate::macros::unsafe_passthrough::unsafe_getter_indirect; +use crate::macros::unsafe_passthrough::{unsafe_getter_indirect, unsafe_setter_indirect}; use flint_sys::{fmpz_poly_mat::fmpz_poly_mat_struct, fq::fq_ctx_struct}; unsafe_getter_indirect!( @@ -25,3 +25,16 @@ unsafe_getter_indirect!( get_fq_ctx_struct, fq_ctx_struct ); + +unsafe_setter_indirect!( + MatPolynomialRingZq, + matrix, + set_fmpz_poly_mat_struct, + fmpz_poly_mat_struct +); +unsafe_setter_indirect!( + MatPolynomialRingZq, + modulus, + set_fq_ctx_struct, + fq_ctx_struct +); diff --git a/src/integer_mod_q/mat_zq/unsafe_functions.rs b/src/integer_mod_q/mat_zq/unsafe_functions.rs index 352a33c64..302358ac1 100644 --- a/src/integer_mod_q/mat_zq/unsafe_functions.rs +++ b/src/integer_mod_q/mat_zq/unsafe_functions.rs @@ -10,12 +10,20 @@ //! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe. use super::MatZq; -use crate::macros::unsafe_passthrough::{unsafe_getter, unsafe_getter_indirect}; -use flint_sys::{fmpz_mod::fmpz_mod_ctx, fmpz_mod_mat::fmpz_mod_mat_struct}; +use crate::macros::unsafe_passthrough::{ + unsafe_getter, unsafe_getter_indirect, unsafe_setter, unsafe_setter_indirect, +}; +use flint_sys::{ + fmpz_mod::fmpz_mod_ctx, + fmpz_mod_mat::{fmpz_mod_mat_clear, fmpz_mod_mat_struct}, +}; unsafe_getter!(MatZq, matrix, fmpz_mod_mat_struct); unsafe_getter_indirect!(MatZq, modulus, get_fmpz_mod_ctx, fmpz_mod_ctx); +unsafe_setter!(MatZq, matrix, fmpz_mod_mat_struct, fmpz_mod_mat_clear); +unsafe_setter_indirect!(MatZq, modulus, set_fmpz_mod_ctx, fmpz_mod_ctx); + #[cfg(test)] mod test_get_fmpz_mod_mat_struct { use super::MatZq; @@ -35,3 +43,28 @@ mod test_get_fmpz_mod_mat_struct { assert_eq!(MatZq::from_str("[[3]] mod 5").unwrap(), mat); } } + +#[cfg(test)] +mod test_set_fmpz_mod_mat_struct { + use super::MatZq; + use flint_sys::{fmpz::fmpz, fmpz_mod_mat::fmpz_mod_mat_init}; + use std::{mem::MaybeUninit, str::FromStr}; + + /// Checks availability of the setter for [`MatZq::matrix`] + /// and its ability to modify [`MatZq`]. + #[test] + fn availability_and_modification() { + let mut mat = MatZq::from_str("[[3]] mod 7").unwrap(); + let mut flint_struct = MaybeUninit::uninit(); + let flint_struct = unsafe { + fmpz_mod_mat_init(flint_struct.as_mut_ptr(), 1, 1, &fmpz(7)); + flint_struct.assume_init() + }; + + unsafe { + mat.set_fmpz_mod_mat_struct(flint_struct); + }; + + assert_eq!(MatZq::new(1, 1, 7), mat); + } +} diff --git a/src/integer_mod_q/modulus/unsafe_functions.rs b/src/integer_mod_q/modulus/unsafe_functions.rs index ecd0a693b..585bbbf15 100644 --- a/src/integer_mod_q/modulus/unsafe_functions.rs +++ b/src/integer_mod_q/modulus/unsafe_functions.rs @@ -11,10 +11,52 @@ use super::Modulus; use crate::macros::unsafe_passthrough::unsafe_getter_mod; -use flint_sys::fmpz_mod::fmpz_mod_ctx; +use flint_sys::fmpz_mod::{fmpz_mod_ctx, fmpz_mod_ctx_clear}; unsafe_getter_mod!(Modulus, modulus, fmpz_mod_ctx); +impl Modulus { + /// Returns a mutable reference to the field `modulus` of type [`Modulus`]. + /// + /// Parameters: + /// - `flint_struct`: value to set the attribute to + /// + /// **WARNING:** The returned struct is part of [`flint_sys`]. + /// Any changes to this object are unsafe and may introduce memory leaks. + /// Please be aware that most moduli are shared across multiple instances and all + /// modifications of this struct will affect any other instance with a reference to this object. + /// + /// This function is a passthrough to enable users of this library to use [`flint_sys`] + /// and with that [FLINT](https://flintlib.org/) functions that might not be covered in our library yet. + /// If this is the case, please consider contributing to this open-source project + /// by opening a Pull Request at [qfall_math](https://github.com/qfall/math) + /// to provide this feature in the future. + /// + /// # Safety + /// Ensure that the old `modulus` does not share any memory with any moduli + /// that might be used in the future. The memory of the old `modulus` is freed + /// using this function. + /// + /// Any [`flint_sys`] struct and function is part of a FFI to the C-library `FLINT`. + /// As `FLINT` is a C-library, it does not provide all memory safety features + /// that Rust and our Wrapper provide. + /// Thus, using functions of [`flint_sys`] can introduce memory leaks. + pub unsafe fn set_fmpz_mod_ctx(&mut self, flint_struct: fmpz_mod_ctx) { + let modulus = std::rc::Rc::::get_mut(&mut self.modulus).unwrap(); + + // free memory of old modulus before new values of modulus are copied + unsafe { fmpz_mod_ctx_clear(modulus) }; + + modulus.add_fxn = flint_struct.add_fxn; + modulus.mod_ = flint_struct.mod_; + modulus.mul_fxn = flint_struct.mul_fxn; + modulus.n = flint_struct.n; + modulus.n_limbs = flint_struct.n_limbs; + modulus.ninv_limbs = flint_struct.ninv_limbs; + modulus.sub_fxn = flint_struct.sub_fxn; + } +} + #[cfg(test)] mod test_get_fmpz_mod_ctx { use super::Modulus; @@ -33,3 +75,28 @@ mod test_get_fmpz_mod_ctx { assert_eq!(Modulus::from(2), modulus); } } + +#[cfg(test)] +mod test_set_fmpz_mod_ctx { + use super::Modulus; + use flint_sys::{fmpz::fmpz, fmpz_mod::fmpz_mod_ctx_init}; + use std::mem::MaybeUninit; + + /// Checks availability of the setter for [`Modulus::modulus`] + /// and its ability to modify [`Modulus`]. + #[test] + #[allow(unused_mut)] + fn availability_and_modification() { + let mut modulus = Modulus::from(3); + + let mut flint_struct = MaybeUninit::uninit(); + let mut flint_struct = unsafe { + fmpz_mod_ctx_init(flint_struct.as_mut_ptr(), &fmpz(2)); + flint_struct.assume_init() + }; + + unsafe { modulus.set_fmpz_mod_ctx(flint_struct) }; + + assert_eq!(Modulus::from(2), modulus); + } +} diff --git a/src/integer_mod_q/modulus_polynomial_ring_zq/unsafe_functions.rs b/src/integer_mod_q/modulus_polynomial_ring_zq/unsafe_functions.rs index 14213136b..41a5e7cbe 100644 --- a/src/integer_mod_q/modulus_polynomial_ring_zq/unsafe_functions.rs +++ b/src/integer_mod_q/modulus_polynomial_ring_zq/unsafe_functions.rs @@ -11,10 +11,54 @@ use super::ModulusPolynomialRingZq; use crate::macros::unsafe_passthrough::unsafe_getter_mod; -use flint_sys::fq::fq_ctx_struct; +use flint_sys::fq::{fq_ctx_clear, fq_ctx_struct}; unsafe_getter_mod!(ModulusPolynomialRingZq, modulus, fq_ctx_struct); +impl ModulusPolynomialRingZq { + /// Returns a mutable reference to the field `modulus` of type [`ModulusPolynomialRingZq`]. + /// + /// Parameters: + /// - `flint_struct`: value to set the attribute to + /// + /// **WARNING:** The returned struct is part of [`flint_sys`]. + /// Any changes to this object are unsafe and may introduce memory leaks. + /// Please be aware that most moduli are shared across multiple instances and all + /// modifications of this struct will affect any other instance with a reference to this object. + /// + /// This function is a passthrough to enable users of this library to use [`flint_sys`] + /// and with that [FLINT](https://flintlib.org/) functions that might not be covered in our library yet. + /// If this is the case, please consider contributing to this open-source project + /// by opening a Pull Request at [qfall_math](https://github.com/qfall/math) + /// to provide this feature in the future. + /// + /// # Safety + /// Ensure that the old `modulus` does not share any memory with any moduli + /// that might be used in the future. The memory of the old `modulus` is freed + /// using this function. + /// + /// Any [`flint_sys`] struct and function is part of a FFI to the C-library `FLINT`. + /// As `FLINT` is a C-library, it does not provide all memory safety features + /// that Rust and our Wrapper provide. + /// Thus, using functions of [`flint_sys`] can introduce memory leaks. + pub unsafe fn set_fq_ctx_struct(&mut self, flint_struct: fq_ctx_struct) { + let modulus = std::rc::Rc::::get_mut(&mut self.modulus).unwrap(); + + // free memory of old modulus before new values of modulus are copied + unsafe { fq_ctx_clear(modulus) }; + + modulus.a = flint_struct.a; + modulus.ctxp = flint_struct.ctxp; + modulus.inv = flint_struct.inv; + modulus.is_conway = flint_struct.is_conway; + modulus.j = flint_struct.j; + modulus.len = flint_struct.len; + modulus.modulus = flint_struct.modulus; + modulus.sparse_modulus = flint_struct.sparse_modulus; + modulus.var = flint_struct.var; + } +} + #[cfg(test)] mod test_get_fq_ctx_struct { use super::ModulusPolynomialRingZq; @@ -37,3 +81,61 @@ mod test_get_fq_ctx_struct { assert_eq!(cmp_mod, modulus); } } + +#[cfg(test)] +mod test_set_fq_ctx_struct { + use super::ModulusPolynomialRingZq; + use crate::{integer::Z, integer_mod_q::Zq, traits::GetCoefficient}; + use flint_sys::{ + fmpz::fmpz, + fmpz_mod::fmpz_mod_ctx_init, + fmpz_mod_poly::{fmpz_mod_poly_init, fmpz_mod_poly_set_coeff_fmpz}, + fq::fq_ctx_init_modulus, + }; + use std::{ffi::CString, mem::MaybeUninit}; + + /// Checks availability of the setter for [`ModulusPolynomialRingZq::modulus`] + /// and its ability to modify [`ModulusPolynomialRingZq`]. + #[test] + #[allow(unused_mut)] + fn availability_and_modification() { + let zq = Zq::from((3, 7)); + let mut test_struct = ModulusPolynomialRingZq::from(zq); + // Setup modulus, i.e. mod 11 + let mut modulus = MaybeUninit::uninit(); + let mut modulus = unsafe { + fmpz_mod_ctx_init(modulus.as_mut_ptr(), &fmpz(11)); + modulus.assume_init() + }; + // Setup ModulusPolynomial, i.e. 7 mod 11 + let mut poly = MaybeUninit::uninit(); + let mut poly = unsafe { + fmpz_mod_poly_init(poly.as_mut_ptr(), &modulus); + poly.assume_init() + }; + unsafe { + fmpz_mod_poly_set_coeff_fmpz(&mut poly, 0, &fmpz(7), &modulus); + }; + // Setup ModPolynomialRingZq + let mut mod_poly_ring_zq = MaybeUninit::uninit(); + let c_string = CString::new("X").unwrap(); + let mod_poly_ring_zq = unsafe { + fq_ctx_init_modulus( + mod_poly_ring_zq.as_mut_ptr(), + &poly, + &modulus, + c_string.as_ptr(), + ); + mod_poly_ring_zq.assume_init() + }; + + unsafe { test_struct.set_fq_ctx_struct(mod_poly_ring_zq) }; + + assert_eq!(Z::from(11), test_struct.get_q()); + assert_eq!(0, test_struct.get_degree()); + assert_eq!( + Z::from(7), + GetCoefficient::::get_coeff(&test_struct, 0).unwrap() + ); + } +} diff --git a/src/integer_mod_q/poly_over_zq/unsafe_functions.rs b/src/integer_mod_q/poly_over_zq/unsafe_functions.rs index 08b3352fc..f0b994f80 100644 --- a/src/integer_mod_q/poly_over_zq/unsafe_functions.rs +++ b/src/integer_mod_q/poly_over_zq/unsafe_functions.rs @@ -10,12 +10,46 @@ //! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe. use super::PolyOverZq; -use crate::macros::unsafe_passthrough::{unsafe_getter, unsafe_getter_indirect}; -use flint_sys::{fmpz_mod::fmpz_mod_ctx, fmpz_mod_poly::fmpz_mod_poly_struct}; +use crate::macros::unsafe_passthrough::{ + unsafe_getter, unsafe_getter_indirect, unsafe_setter_indirect, +}; +use flint_sys::{ + fmpz_mod::fmpz_mod_ctx, + fmpz_mod_poly::{fmpz_mod_poly_clear, fmpz_mod_poly_struct}, +}; unsafe_getter!(PolyOverZq, poly, fmpz_mod_poly_struct); unsafe_getter_indirect!(PolyOverZq, modulus, get_fmpz_mod_ctx, fmpz_mod_ctx); +impl PolyOverZq { + /// Sets the field `poly` of type [`PolyOverZq`] to `flint_struct`. + /// + /// Parameters: + /// - `flint_struct`: value to set the attribute to + /// + /// This function is a passthrough to enable users of this library to use [`flint_sys`] + /// and with that [FLINT](https://flintlib.org/) functions that might not be covered in our library yet. + /// If this is the case, please consider contributing to this open-source project + /// by opening a Pull Request at [qfall_math](https://github.com/qfall/math) + /// to provide this feature in the future. + /// + /// # Safety + /// Ensure that the old struct does not share any memory with any other structs + /// that might be used in the future. The memory of the old struct is freed + /// using this function. + /// + /// Any [`flint_sys`] struct and function is part of a FFI to the C-library `FLINT`. + /// As `FLINT` is a C-library, it does not provide all memory safety features + /// that Rust and our Wrapper provide. + /// Thus, using functions of [`flint_sys`] can introduce memory leaks. + pub unsafe fn set_fmpz_mod_poly_struct(&mut self, flint_struct: fmpz_mod_poly_struct) { + fmpz_mod_poly_clear(&mut self.poly, self.modulus.get_fmpz_mod_ctx_struct()); + + self.poly = flint_struct; + } +} +unsafe_setter_indirect!(PolyOverZq, modulus, set_fmpz_mod_ctx, fmpz_mod_ctx); + #[cfg(test)] mod test_get_fmpz_mod_poly_struct { use super::PolyOverZq; @@ -35,3 +69,30 @@ mod test_get_fmpz_mod_poly_struct { assert_eq!(PolyOverZq::from((5, 7)), poly); } } + +#[cfg(test)] +mod test_set_fmpz_mod_poly_struct { + use super::PolyOverZq; + use crate::integer_mod_q::Modulus; + use flint_sys::fmpz_mod_poly::fmpz_mod_poly_init; + use std::mem::MaybeUninit; + + /// Checks availability of the setter for [`PolyOverZq::poly`] + /// and its ability to modify [`PolyOverZq`]. + #[test] + #[allow(unused_mut)] + fn availability_and_modification() { + let mut poly = PolyOverZq::from((3, 7)); + + let modulus = Modulus::from(7); + let mut flint_struct = MaybeUninit::uninit(); + let flint_struct = unsafe { + fmpz_mod_poly_init(flint_struct.as_mut_ptr(), modulus.get_fmpz_mod_ctx_struct()); + flint_struct.assume_init() + }; + + unsafe { poly.set_fmpz_mod_poly_struct(flint_struct) }; + + assert_eq!(PolyOverZq::from((0, 7)), poly); + } +} diff --git a/src/integer_mod_q/polynomial_ring_zq/unsafe_functions.rs b/src/integer_mod_q/polynomial_ring_zq/unsafe_functions.rs index ca3208bfd..e1ea4c305 100644 --- a/src/integer_mod_q/polynomial_ring_zq/unsafe_functions.rs +++ b/src/integer_mod_q/polynomial_ring_zq/unsafe_functions.rs @@ -10,7 +10,7 @@ //! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe. use super::PolynomialRingZq; -use crate::macros::unsafe_passthrough::unsafe_getter_indirect; +use crate::macros::unsafe_passthrough::{unsafe_getter_indirect, unsafe_setter_indirect}; use flint_sys::{fmpz_poly::fmpz_poly_struct, fq::fq_ctx_struct}; unsafe_getter_indirect!( @@ -20,3 +20,11 @@ unsafe_getter_indirect!( fmpz_poly_struct ); unsafe_getter_indirect!(PolynomialRingZq, modulus, get_fq_ctx_struct, fq_ctx_struct); + +unsafe_setter_indirect!( + PolynomialRingZq, + poly, + set_fmpz_poly_struct, + fmpz_poly_struct +); +unsafe_setter_indirect!(PolynomialRingZq, modulus, set_fq_ctx_struct, fq_ctx_struct); diff --git a/src/integer_mod_q/z_q/unsafe_functions.rs b/src/integer_mod_q/z_q/unsafe_functions.rs index 1a0c97866..5e8662934 100644 --- a/src/integer_mod_q/z_q/unsafe_functions.rs +++ b/src/integer_mod_q/z_q/unsafe_functions.rs @@ -10,8 +10,11 @@ //! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe. use super::Zq; -use crate::macros::unsafe_passthrough::unsafe_getter_indirect; +use crate::macros::unsafe_passthrough::{unsafe_getter_indirect, unsafe_setter_indirect}; use flint_sys::{fmpz::fmpz, fmpz_mod::fmpz_mod_ctx}; unsafe_getter_indirect!(Zq, value, get_fmpz, fmpz); unsafe_getter_indirect!(Zq, modulus, get_fmpz_mod_ctx, fmpz_mod_ctx); + +unsafe_setter_indirect!(Zq, value, set_fmpz, fmpz); +unsafe_setter_indirect!(Zq, modulus, set_fmpz_mod_ctx, fmpz_mod_ctx); diff --git a/src/macros/unsafe_passthrough.rs b/src/macros/unsafe_passthrough.rs index f0a14105d..611d5090b 100644 --- a/src/macros/unsafe_passthrough.rs +++ b/src/macros/unsafe_passthrough.rs @@ -133,3 +133,93 @@ macro_rules! unsafe_getter_indirect { pub(crate) use unsafe_getter; pub(crate) use unsafe_getter_indirect; pub(crate) use unsafe_getter_mod; + +/// Implements a setter-function for a field in a struct. +/// +/// Input parameters: +/// - `struct`: the struct for which the setter is implemented (e.g. [`Z`](crate::integer::Z), ...). +/// - `attribute_name`: the name of the field (e.g. `value`, ...). +/// - `attribute_type`: the struct resp. type of the field (e.g. [`fmpz`](flint_sys::fmpz::fmpz)) +/// +/// Returns the Implementation code for the given $struct with the signature: +/// ```impl $struct``` +macro_rules! unsafe_setter { + ($struct:ident, $attribute_name:meta, $attribute_type:ty, $clear_function:ident) => { + impl $struct { + paste::paste! { + #[doc = "Sets the field `" $attribute_name "` of type [`" $attribute_type "`] to `flint_struct`."] + /// + /// Parameters: + /// - `flint_struct`: value to set the attribute to + /// + /// This function is a passthrough to enable users of this library to use [`flint_sys`] + /// and with that [FLINT](https://flintlib.org/) functions that might not be covered in our library yet. + /// If this is the case, please consider contributing to this open-source project + /// by opening a Pull Request at [qfall_math](https://github.com/qfall/math) + /// to provide this feature in the future. + /// + /// # Safety + /// Ensure that the old struct does not share any memory with any other structs + /// that might be used in the future. The memory of the old struct is freed + /// using this function. + /// + /// Any [`flint_sys`] struct and function is part of a FFI to the C-library `FLINT`. + /// As `FLINT` is a C-library, it does not provide all memory safety features + /// that Rust and our Wrapper provide. + /// Thus, using functions of [`flint_sys`] can introduce memory leaks. + pub unsafe fn [](&mut self, flint_struct: $attribute_type) { + $clear_function(&mut self.$attribute_name); + + self.$attribute_name = flint_struct; + } + } + } + }; +} + +/// Implements a setter-function for a field in a struct, which itself has an +/// unsafe setter for an underlying struct. +/// +/// Input parameters: +/// - `struct`: the struct for which the setter is implemented (e.g. [`Z`](crate::integer::Z), ...). +/// - `attribute_name`: the name of the field (e.g. `value`, ...). +/// - `function_name`: the name of the function, which is called to gather +/// the [`flint_sys`] struct (e.g. [crate::integer::Z::set_fmpz]) +/// - `attribute_type`: the struct resp. type of the field (e.g. [`fmpz`](flint_sys::fmpz::fmpz)) +/// +/// Returns the Implementation code for the given $struct with the signature: +/// ```impl $struct``` +macro_rules! unsafe_setter_indirect { + ($struct:ident, $attribute_name:meta, $function_name:ident, $attribute_type:ty) => { + impl $struct { + paste::paste! { + #[doc = "Sets the field [`" $attribute_type "`] to `flint_struct` by calling `" $function_name "` on `" $attribute_name "`."] + /// + /// Parameters: + /// - `flint_struct`: value to set the attribute to + /// + /// This function is a passthrough to enable users of this library to use [`flint_sys`] + /// and with that [FLINT](https://flintlib.org/) functions that might not be covered in our library yet. + /// If this is the case, please consider contributing to this open-source project + /// by opening a Pull Request at [qfall_math](https://github.com/qfall/math) + /// to provide this feature in the future. + /// + /// # Safety + /// Ensure that the old struct does not share any memory with any other structs + /// that might be used in the future. The memory of the old struct is freed + /// using this function. + /// + /// Any [`flint_sys`] struct and function is part of a FFI to the C-library `FLINT`. + /// As `FLINT` is a C-library, it does not provide all memory safety features + /// that Rust and our Wrapper provide. + /// Thus, using functions of [`flint_sys`] can introduce memory leaks. + pub unsafe fn [](&mut self, flint_struct: $attribute_type) { + self.$attribute_name.$function_name(flint_struct) + } + } + } + }; +} + +pub(crate) use unsafe_setter; +pub(crate) use unsafe_setter_indirect; diff --git a/src/rational/mat_q/unsafe_functions.rs b/src/rational/mat_q/unsafe_functions.rs index c672c43ea..0136acee1 100644 --- a/src/rational/mat_q/unsafe_functions.rs +++ b/src/rational/mat_q/unsafe_functions.rs @@ -10,11 +10,13 @@ //! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe. use super::MatQ; -use crate::macros::unsafe_passthrough::unsafe_getter; -use flint_sys::fmpq_mat::fmpq_mat_struct; +use crate::macros::unsafe_passthrough::{unsafe_getter, unsafe_setter}; +use flint_sys::fmpq_mat::{fmpq_mat_clear, fmpq_mat_struct}; unsafe_getter!(MatQ, matrix, fmpq_mat_struct); +unsafe_setter!(MatQ, matrix, fmpq_mat_struct, fmpq_mat_clear); + #[cfg(test)] mod test_get_fmpq_mat_struct { use super::MatQ; @@ -40,3 +42,28 @@ mod test_get_fmpq_mat_struct { assert_eq!(value, mat.get_entry(0, 0).unwrap()); } } + +#[cfg(test)] +mod test_set_fmpq_mat_struct { + use super::MatQ; + use crate::{rational::Q, traits::MatrixGetEntry}; + use flint_sys::fmpq_mat::fmpq_mat_init; + use std::{mem::MaybeUninit, str::FromStr}; + + /// Checks availability of the setter for [`MatQ::matrix`] + /// and its ability to modify [`MatQ`]. + #[test] + #[allow(unused_mut)] + fn availability_and_modification() { + let mut mat = MatQ::from_str("[[1]]").unwrap(); + let mut flint_struct = MaybeUninit::uninit(); + let flint_struct = unsafe { + fmpq_mat_init(flint_struct.as_mut_ptr(), 1, 1); + flint_struct.assume_init() + }; + + unsafe { mat.set_fmpq_mat_struct(flint_struct) }; + + assert_eq!(Q::ZERO, mat.get_entry(0, 0).unwrap()); + } +} diff --git a/src/rational/poly_over_q/unsafe_functions.rs b/src/rational/poly_over_q/unsafe_functions.rs index 0c3782e33..0c72e511b 100644 --- a/src/rational/poly_over_q/unsafe_functions.rs +++ b/src/rational/poly_over_q/unsafe_functions.rs @@ -10,11 +10,13 @@ //! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe. use super::PolyOverQ; -use crate::macros::unsafe_passthrough::unsafe_getter; -use flint_sys::fmpq_poly::fmpq_poly_struct; +use crate::macros::unsafe_passthrough::{unsafe_getter, unsafe_setter}; +use flint_sys::fmpq_poly::{fmpq_poly_clear, fmpq_poly_struct}; unsafe_getter!(PolyOverQ, poly, fmpq_poly_struct); +unsafe_setter!(PolyOverQ, poly, fmpq_poly_struct, fmpq_poly_clear); + #[cfg(test)] mod test_get_fmpq_poly_struct { use super::PolyOverQ; @@ -36,3 +38,27 @@ mod test_get_fmpq_poly_struct { assert_eq!(PolyOverQ::from(2), poly); } } + +#[cfg(test)] +mod test_set_fmpq_poly_struct { + use super::PolyOverQ; + use flint_sys::fmpq_poly::fmpq_poly_init; + use std::mem::MaybeUninit; + + /// Checks availability of the setter for [`PolyOverQ::poly`] + /// and its ability to modify [`PolyOverQ`]. + #[test] + #[allow(unused_mut)] + fn availability_and_modification() { + let mut poly = PolyOverQ::from(1); + let mut flint_struct = MaybeUninit::uninit(); + let flint_struct = unsafe { + fmpq_poly_init(flint_struct.as_mut_ptr()); + flint_struct.assume_init() + }; + + unsafe { poly.set_fmpq_poly_struct(flint_struct) }; + + assert_eq!(PolyOverQ::from(0), poly); + } +} diff --git a/src/rational/q/unsafe_functions.rs b/src/rational/q/unsafe_functions.rs index 92d64c736..0ecc3f53c 100644 --- a/src/rational/q/unsafe_functions.rs +++ b/src/rational/q/unsafe_functions.rs @@ -10,11 +10,13 @@ //! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe. use super::Q; -use crate::macros::unsafe_passthrough::unsafe_getter; -use flint_sys::fmpq::fmpq; +use crate::macros::unsafe_passthrough::{unsafe_getter, unsafe_setter}; +use flint_sys::fmpq::{fmpq, fmpq_clear}; unsafe_getter!(Q, value, fmpq); +unsafe_setter!(Q, value, fmpq, fmpq_clear); + #[cfg(test)] mod test_get_fmpq { use super::Q; @@ -34,3 +36,25 @@ mod test_get_fmpq { assert_eq!(Q::from(2), rational); } } + +#[cfg(test)] +mod test_set_fmpq { + use super::Q; + use flint_sys::{fmpq::fmpq, fmpz::fmpz}; + + /// Checks availability of the setter for [`Q::value`] + /// and its ability to modify [`Q`]. + #[test] + #[allow(unused_mut)] + fn availability_and_modification() { + let mut rational = Q::from(1); + let flint_struct = fmpq { + num: fmpz(2), + den: fmpz(1), + }; + + unsafe { rational.set_fmpq(flint_struct) }; + + assert_eq!(Q::from(2), rational); + } +}