Skip to content

Commit 6f86a92

Browse files
committed
Move utility functions only used by io module
1 parent c273908 commit 6f86a92

File tree

8 files changed

+131
-130
lines changed

8 files changed

+131
-130
lines changed

splashsurf_lib/src/io.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use nalgebra::Vector3;
66
use std::path::Path;
77

88
pub mod bgeo_format;
9+
mod io_utils;
910
pub mod json_format;
1011
pub mod obj_format;
1112
pub mod ply_format;

splashsurf_lib/src/io/bgeo_format.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Helper functions for the BGEO file format
22
3+
use crate::io::io_utils::IteratorExt;
34
use crate::mesh::{AttributeData, MeshAttribute};
4-
use crate::utils::IteratorExt;
5-
use crate::{Real, utils};
5+
use crate::{Real, io::io_utils};
66
use anyhow::{Context, anyhow};
77
use flate2::Compression;
88
use flate2::read::GzDecoder;
@@ -340,15 +340,15 @@ impl AttributeStorage {
340340
/// Tries to convert this BGEO attribute storage into a mesh [`AttributeData`] storage
341341
fn try_into_attribute_data<R: Real>(&self) -> Result<AttributeData<R>, anyhow::Error> {
342342
match self {
343-
AttributeStorage::Int(data) => utils::try_convert_scalar_slice(data, u64::from_i32)
343+
AttributeStorage::Int(data) => io_utils::try_convert_scalar_slice(data, u64::from_i32)
344344
.map(|v| AttributeData::ScalarU64(v))
345345
.context(anyhow!("failed to convert integer attribute")),
346-
AttributeStorage::Float(data) => utils::try_convert_scalar_slice(data, R::from_f32)
346+
AttributeStorage::Float(data) => io_utils::try_convert_scalar_slice(data, R::from_f32)
347347
.map(|v| AttributeData::ScalarReal(v))
348348
.context(anyhow!("failed to convert float attribute")),
349349
AttributeStorage::Vector(n, data) => {
350350
if *n == 3 {
351-
utils::try_convert_scalar_slice_to_vectors(data, R::from_f32)
351+
io_utils::try_convert_scalar_slice_to_vectors(data, R::from_f32)
352352
.map(|v| AttributeData::Vector3Real(v))
353353
.context(anyhow!("failed to convert vector attribute"))
354354
} else {

splashsurf_lib/src/io/io_utils.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
use anyhow::{Context, anyhow};
2+
use nalgebra::{SVector, Scalar};
3+
use num_traits::Zero;
4+
use std::fmt::Debug;
5+
6+
/// Converts a slice of scalar values to a vector of the same length, returns an error if conversion fails
7+
pub fn try_convert_scalar_slice<
8+
ScalarFrom: Copy + Debug,
9+
ScalarTo,
10+
F: Fn(ScalarFrom) -> Option<ScalarTo>,
11+
>(
12+
values: &[ScalarFrom],
13+
f: F,
14+
) -> Result<Vec<ScalarTo>, anyhow::Error> {
15+
values
16+
.iter()
17+
.copied()
18+
.map(|v| {
19+
f(v).ok_or_else(|| {
20+
anyhow!(
21+
"failed to convert value {:?} from type {} to {}",
22+
v,
23+
std::any::type_name::<ScalarFrom>(),
24+
std::any::type_name::<ScalarTo>()
25+
)
26+
})
27+
})
28+
.try_collect_with_capacity(values.len())
29+
}
30+
31+
/// Converts a slice of scalar values to a vector of [`nalgebra::SVector`], returns an error if conversion fails or the input slice's length is not a multiple of the vector length.
32+
pub fn try_convert_scalar_slice_to_vectors<
33+
const N: usize,
34+
ScalarFrom: Copy + Debug,
35+
ScalarTo: Scalar + Zero,
36+
F: Fn(ScalarFrom) -> Option<ScalarTo>,
37+
>(
38+
values: &[ScalarFrom],
39+
f: F,
40+
) -> Result<Vec<SVector<ScalarTo, N>>, anyhow::Error> {
41+
{
42+
if values.len() % N != 0 {
43+
Err(anyhow!("input slice length is not a multiple of {}", N))
44+
} else {
45+
values
46+
.chunks_exact(N)
47+
.map(|v| {
48+
let mut v_out = SVector::zeros();
49+
for i in 0..N {
50+
v_out[i] = f(v[i]).ok_or_else(|| {
51+
anyhow!(
52+
"failed to convert value {:?} from type {} to {}",
53+
v,
54+
std::any::type_name::<ScalarFrom>(),
55+
std::any::type_name::<ScalarTo>()
56+
)
57+
})?;
58+
}
59+
Ok(v_out)
60+
})
61+
.try_collect_with_capacity(values.len() / N)
62+
}
63+
}
64+
.context(anyhow!(
65+
"failed to convert scalar slice to vectors of length {}",
66+
N
67+
))
68+
}
69+
70+
#[cfg(test)]
71+
mod tests {
72+
use num_traits::FromPrimitive;
73+
#[test]
74+
fn test_try_convert_scalar_slice() {
75+
let values = vec![1, -1];
76+
assert!(super::try_convert_scalar_slice(&values, u64::from_i32).is_err());
77+
let values = vec![1, -1];
78+
assert_eq!(
79+
super::try_convert_scalar_slice(&values, f32::from_i64).unwrap(),
80+
vec![1.0, -1.0]
81+
);
82+
}
83+
}
84+
85+
/// "Convert" an empty vector to preserve allocated memory if size and alignment matches
86+
/// See https://users.rust-lang.org/t/pattern-how-to-reuse-a-vec-str-across-loop-iterations/61657/5
87+
/// See https://github.com/rust-lang/rfcs/pull/2802
88+
#[allow(unused)]
89+
pub(crate) fn recycle<A, B>(mut v: Vec<A>) -> Vec<B> {
90+
v.clear();
91+
v.into_iter().map(|_| unreachable!()).collect()
92+
}
93+
94+
/// Useful extension methods for iterators
95+
pub(crate) trait IteratorExt {
96+
/// Tries to collect the items of the iterator into a `Vec` that reserves the given capacity and stops as soon as an error is encountered
97+
///
98+
/// Motivation: <https://github.com/rust-lang/rust/issues/48994>
99+
fn try_collect_with_capacity<T, E>(self, capacity: usize) -> Result<Vec<T>, E>
100+
where
101+
Self: Sized + Iterator<Item = Result<T, E>>;
102+
}
103+
104+
impl<Iter: Iterator> IteratorExt for Iter {
105+
fn try_collect_with_capacity<T, E>(mut self, capacity: usize) -> Result<Vec<T>, E>
106+
where
107+
Self: Sized + Iterator<Item = Result<T, E>>,
108+
{
109+
self.try_fold(Vec::with_capacity(capacity), |mut vec, item| {
110+
vec.push(item?);
111+
Ok(vec)
112+
})
113+
}
114+
}

splashsurf_lib/src/io/json_format.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Helper functions for the JSON file format
22
3-
use crate::utils::IteratorExt;
3+
use crate::io::io_utils::IteratorExt;
44
use crate::{Real, RealConvert};
55
use anyhow::{Context, anyhow};
66
use nalgebra::Vector3;

splashsurf_lib/src/io/obj_format.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::mesh::{
44
AttributeData, CellConnectivity, Mesh3d, MeshAttribute, MeshWithData, TriMesh3d,
55
};
6-
use crate::{Real, profile, utils};
6+
use crate::{Real, io::io_utils, profile};
77
use anyhow::Context;
88
use nalgebra::Vector3;
99
use std::fs;
@@ -92,7 +92,7 @@ pub fn surface_mesh_from_obj<R: Real, P: AsRef<Path>>(
9292
let mut buffer_string = String::new();
9393

9494
loop {
95-
let mut buffer = utils::recycle(outer_buffer);
95+
let mut buffer = io_utils::recycle(outer_buffer);
9696

9797
let read = reader.read_line(&mut buffer_string)?;
9898
if read == 0 {
@@ -134,7 +134,7 @@ pub fn surface_mesh_from_obj<R: Real, P: AsRef<Path>>(
134134
normals.push(buffer_to_vec3(&buffer)?);
135135
}
136136

137-
outer_buffer = utils::recycle(buffer);
137+
outer_buffer = io_utils::recycle(buffer);
138138
buffer_string.clear();
139139
}
140140

splashsurf_lib/src/io/ply_format.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
//! Helper functions for the PLY file format
22
3+
use crate::io::io_utils::IteratorExt;
34
use crate::mesh::{
45
AttributeData, CellConnectivity, Mesh3d, MeshAttribute, MeshWithData, TriMesh3d,
56
};
6-
use crate::utils::IteratorExt;
77
use crate::{Real, profile};
88
use anyhow::{Context, anyhow};
99
use nalgebra::Vector3;

splashsurf_lib/src/io/vtk_format.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Helper functions for the VTK file format
22
3+
use crate::io::io_utils::IteratorExt;
34
use crate::mesh::{AttributeData, IntoVtkDataSet, MeshAttribute, MeshWithData, TriMesh3d};
4-
use crate::utils::IteratorExt;
5-
use crate::{Real, RealConvert, profile, utils};
5+
use crate::{Real, RealConvert, io::io_utils, profile};
66
use anyhow::{Context, anyhow};
77
use nalgebra::Vector3;
88
use std::borrow::Cow;
@@ -318,11 +318,11 @@ fn try_convert_io_buffer_to_attribute<R: Real>(
318318
) -> Result<AttributeData<R>, anyhow::Error> {
319319
match num_comp {
320320
1 => match &io_buffer {
321-
IOBuffer::U32(vec) => utils::try_convert_scalar_slice(vec, R::from_u32)
321+
IOBuffer::U32(vec) => io_utils::try_convert_scalar_slice(vec, R::from_u32)
322322
.map(|v| AttributeData::ScalarReal(v)),
323-
IOBuffer::F32(vec) => utils::try_convert_scalar_slice(vec, R::from_f32)
323+
IOBuffer::F32(vec) => io_utils::try_convert_scalar_slice(vec, R::from_f32)
324324
.map(|v| AttributeData::ScalarReal(v)),
325-
IOBuffer::F64(vec) => utils::try_convert_scalar_slice(vec, R::from_f64)
325+
IOBuffer::F64(vec) => io_utils::try_convert_scalar_slice(vec, R::from_f64)
326326
.map(|v| AttributeData::ScalarReal(v)),
327327
_ => Err(anyhow!("Unsupported IOBuffer scalar data type")),
328328
},
@@ -346,7 +346,7 @@ fn try_convert_io_buffer_to_attribute<R: Real>(
346346
fn particles_from_coords<RealOut: Real, RealIn: Real>(
347347
coords: &[RealIn],
348348
) -> Result<Vec<Vector3<RealOut>>, anyhow::Error> {
349-
utils::try_convert_scalar_slice_to_vectors(coords, |v| v.try_convert())
349+
io_utils::try_convert_scalar_slice_to_vectors(coords, |v| v.try_convert())
350350
.context(anyhow!("failed to convert particle coordinates"))
351351
}
352352

splashsurf_lib/src/utils.rs

Lines changed: 0 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,8 @@
11
//! Internal helper functions and types
22
3-
use anyhow::{Context, anyhow};
43
use log::info;
5-
use nalgebra::{SVector, Scalar};
6-
use num_traits::Zero;
74
use rayon::prelude::*;
85
use std::cell::UnsafeCell;
9-
use std::fmt::Debug;
10-
11-
/// Converts a slice of scalar values to a vector of the same length, returns an error if conversion fails
12-
pub fn try_convert_scalar_slice<
13-
ScalarFrom: Copy + Debug,
14-
ScalarTo,
15-
F: Fn(ScalarFrom) -> Option<ScalarTo>,
16-
>(
17-
values: &[ScalarFrom],
18-
f: F,
19-
) -> Result<Vec<ScalarTo>, anyhow::Error> {
20-
values
21-
.iter()
22-
.copied()
23-
.map(|v| {
24-
f(v).ok_or_else(|| {
25-
anyhow!(
26-
"failed to convert value {:?} from type {} to {}",
27-
v,
28-
std::any::type_name::<ScalarFrom>(),
29-
std::any::type_name::<ScalarTo>()
30-
)
31-
})
32-
})
33-
.try_collect_with_capacity(values.len())
34-
}
35-
36-
/// Converts a slice of scalar values to a vector of [`nalgebra::SVector`], returns an error if conversion fails or the input slice's length is not a multiple of the vector length.
37-
pub fn try_convert_scalar_slice_to_vectors<
38-
const N: usize,
39-
ScalarFrom: Copy + Debug,
40-
ScalarTo: Scalar + Zero,
41-
F: Fn(ScalarFrom) -> Option<ScalarTo>,
42-
>(
43-
values: &[ScalarFrom],
44-
f: F,
45-
) -> Result<Vec<SVector<ScalarTo, N>>, anyhow::Error> {
46-
{
47-
if values.len() % N != 0 {
48-
Err(anyhow!("input slice length is not a multiple of {}", N))
49-
} else {
50-
values
51-
.chunks_exact(N)
52-
.map(|v| {
53-
let mut v_out = SVector::zeros();
54-
for i in 0..N {
55-
v_out[i] = f(v[i]).ok_or_else(|| {
56-
anyhow!(
57-
"failed to convert value {:?} from type {} to {}",
58-
v,
59-
std::any::type_name::<ScalarFrom>(),
60-
std::any::type_name::<ScalarTo>()
61-
)
62-
})?;
63-
}
64-
Ok(v_out)
65-
})
66-
.try_collect_with_capacity(values.len() / N)
67-
}
68-
}
69-
.context(anyhow!(
70-
"failed to convert scalar slice to vectors of length {}",
71-
N
72-
))
73-
}
74-
75-
#[cfg(test)]
76-
mod tests {
77-
use num_traits::FromPrimitive;
78-
#[test]
79-
fn test_try_convert_scalar_slice() {
80-
let values = vec![1, -1];
81-
assert!(super::try_convert_scalar_slice(&values, u64::from_i32).is_err());
82-
let values = vec![1, -1];
83-
assert_eq!(
84-
super::try_convert_scalar_slice(&values, f32::from_i64).unwrap(),
85-
vec![1.0, -1.0]
86-
);
87-
}
88-
}
89-
90-
/// "Convert" an empty vector to preserve allocated memory if size and alignment matches
91-
/// See https://users.rust-lang.org/t/pattern-how-to-reuse-a-vec-str-across-loop-iterations/61657/5
92-
/// See https://github.com/rust-lang/rfcs/pull/2802
93-
#[allow(unused)]
94-
pub(crate) fn recycle<A, B>(mut v: Vec<A>) -> Vec<B> {
95-
v.clear();
96-
v.into_iter().map(|_| unreachable!()).collect()
97-
}
986

997
/// Macro version of Option::map that allows using e.g. using the ?-operator in the map expression
1008
///
@@ -111,28 +19,6 @@ macro_rules! map_option {
11119
};
11220
}
11321

114-
/// Useful extension methods for iterators
115-
pub(crate) trait IteratorExt {
116-
/// Tries to collect the items of the iterator into a `Vec` that reserves the given capacity and stops as soon as an error is encountered
117-
///
118-
/// Motivation: <https://github.com/rust-lang/rust/issues/48994>
119-
fn try_collect_with_capacity<T, E>(self, capacity: usize) -> Result<Vec<T>, E>
120-
where
121-
Self: Sized + Iterator<Item = Result<T, E>>;
122-
}
123-
124-
impl<Iter: Iterator> IteratorExt for Iter {
125-
fn try_collect_with_capacity<T, E>(mut self, capacity: usize) -> Result<Vec<T>, E>
126-
where
127-
Self: Sized + Iterator<Item = Result<T, E>>,
128-
{
129-
self.try_fold(Vec::with_capacity(capacity), |mut vec, item| {
130-
vec.push(item?);
131-
Ok(vec)
132-
})
133-
}
134-
}
135-
13622
/// Wrapper for unsafe shared mutable access to a slice, disjoint access has to be ensured separately
13723
/// Implementation based on: <https://stackoverflow.com/a/65182786/929037>
13824
#[derive(Copy, Clone)]

0 commit comments

Comments
 (0)