use core::fmt;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct JacobianIndexError {
pub row: usize,
pub column: usize,
pub rows: usize,
pub columns: usize,
}
impl fmt::Display for JacobianIndexError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"Jacobian index ({}, {}) is outside {} by {}",
self.row, self.column, self.rows, self.columns
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for JacobianIndexError {}
pub struct JacobianMut<'a, T> {
data: &'a mut [T],
rows: usize,
columns: usize,
leading_dimension: usize,
}
impl<'a, T> JacobianMut<'a, T> {
pub(crate) fn new(
data: &'a mut [T],
rows: usize,
columns: usize,
leading_dimension: usize,
) -> Option<Self> {
if leading_dimension < rows || leading_dimension.checked_mul(columns)? > data.len() {
return None;
}
Some(Self {
data,
rows,
columns,
leading_dimension,
})
}
pub const fn rows(&self) -> usize {
self.rows
}
pub const fn columns(&self) -> usize {
self.columns
}
pub const fn cols(&self) -> usize {
self.columns
}
pub const fn leading_dimension(&self) -> usize {
self.leading_dimension
}
pub fn get(&self, row: usize, column: usize) -> Option<&T> {
self.index(row, column).map(|index| &self.data[index])
}
pub fn get_mut(&mut self, row: usize, column: usize) -> Option<&mut T> {
self.index(row, column).map(|index| &mut self.data[index])
}
pub fn set(&mut self, row: usize, column: usize, value: T) -> Result<(), JacobianIndexError> {
let index = self.index(row, column).ok_or(JacobianIndexError {
row,
column,
rows: self.rows,
columns: self.columns,
})?;
self.data[index] = value;
Ok(())
}
pub fn as_column_major_slice_mut(&mut self) -> &mut [T] {
self.data
}
fn index(&self, row: usize, column: usize) -> Option<usize> {
if row >= self.rows || column >= self.columns {
return None;
}
column
.checked_mul(self.leading_dimension)
.and_then(|base| base.checked_add(row))
}
}
#[cfg(test)]
mod tests {
use super::JacobianMut;
#[test]
fn indexing_is_column_major_and_padding_is_not_logical() {
let mut data = [0_i32; 8];
let mut view = JacobianMut::new(&mut data, 2, 2, 4).unwrap();
view.set(1, 1, 7).unwrap();
assert_eq!(view.get(1, 1), Some(&7));
assert!(view.get(2, 0).is_none());
assert_eq!(view.as_column_major_slice_mut()[5], 7);
}
}