ferray_ma/mask_ops.rs
1// ferray-ma: Mask manipulation utilities (REQ-15, REQ-16, REQ-17)
2//
3// harden_mask, soften_mask, getmask, getdata, is_masked, count_masked
4
5use ferray_core::Array;
6use ferray_core::dimension::Dimension;
7use ferray_core::dtype::Element;
8use ferray_core::error::FerrayResult;
9
10use crate::MaskedArray;
11
12impl<T: Element, D: Dimension> MaskedArray<T, D> {
13 /// Harden the mask: prevent subsequent assignments from clearing mask bits.
14 ///
15 /// After this call, any attempt to set a mask bit to `false` via
16 /// `set_mask_flat` or `set_mask` will be silently ignored.
17 ///
18 /// # Errors
19 /// This function does not currently error but returns `Result` for API
20 /// consistency.
21 pub const fn harden_mask(&mut self) -> FerrayResult<()> {
22 self.hard_mask = true;
23 Ok(())
24 }
25
26 /// Soften the mask: allow subsequent assignments to clear mask bits.
27 ///
28 /// # Errors
29 /// This function does not currently error but returns `Result` for API
30 /// consistency.
31 pub const fn soften_mask(&mut self) -> FerrayResult<()> {
32 self.hard_mask = false;
33 Ok(())
34 }
35}
36
37/// Return the mask array of a masked array.
38///
39/// This is equivalent to `ma.mask()` but provided as a free function
40/// for API parity with `NumPy`'s `np.ma.getmask`.
41///
42/// # Errors
43/// This function does not currently error but returns `Result` for API
44/// consistency.
45pub fn getmask<T: Element, D: Dimension>(ma: &MaskedArray<T, D>) -> FerrayResult<Array<bool, D>> {
46 Ok(ma.mask().clone())
47}
48
49/// Return the underlying data array of a masked array.
50///
51/// This is equivalent to `ma.data()` but provided as a free function
52/// for API parity with `NumPy`'s `np.ma.getdata`.
53///
54/// # Errors
55/// This function does not currently error but returns `Result` for API
56/// consistency.
57pub fn getdata<T: Element + Copy, D: Dimension>(
58 ma: &MaskedArray<T, D>,
59) -> FerrayResult<Array<T, D>> {
60 Ok(ma.data().clone())
61}
62
63/// Return `true` if any element in the masked array is masked.
64///
65/// # Errors
66/// This function does not currently error but returns `Result` for API
67/// consistency.
68pub fn is_masked<T: Element, D: Dimension>(ma: &MaskedArray<T, D>) -> FerrayResult<bool> {
69 Ok(ma.mask().iter().any(|m| *m))
70}
71
72/// Count the number of masked elements, optionally along an axis.
73///
74/// If `axis` is `None`, returns the total count of masked elements as a
75/// single-element vector. If an axis is specified, this function currently
76/// returns the total count (axis-specific counting for multi-dimensional
77/// masked arrays is a future enhancement).
78///
79/// # Errors
80/// This function does not currently error but returns `Result` for API
81/// consistency.
82pub fn count_masked<T: Element, D: Dimension>(
83 ma: &MaskedArray<T, D>,
84 _axis: Option<usize>,
85) -> FerrayResult<usize> {
86 let count = ma.mask().iter().filter(|m| **m).count();
87 Ok(count)
88}