diff --git a/nalgebra-sparse/src/io/matrix_market.rs b/nalgebra-sparse/src/io/matrix_market.rs index d00a873d..8acedd77 100644 --- a/nalgebra-sparse/src/io/matrix_market.rs +++ b/nalgebra-sparse/src/io/matrix_market.rs @@ -508,9 +508,9 @@ mod internal { /// When matrix is a Hermitian matrix, it will convert itself to its conjugate. fn conjugate(self) -> Result; /// Returns the name of SupportedMatrixMarketScalar, used when write the matrix - fn typename() -> &'static str; - /// Convert the data to string - fn to_matrixmarket_string(&self) -> String; + fn typename() -> &'static [u8]; + /// Convert the data to bytes + fn to_matrixmarket_bytes(&self) -> Vec; } pub trait SupportedMatrixMarketExport { @@ -574,12 +574,12 @@ macro_rules! mm_int_impl { Ok(-self) } #[inline] - fn typename() -> &'static str { - "integer" + fn typename() -> &'static [u8] { + b"integer" } #[inline] - fn to_matrixmarket_string(&self) -> String { - self.to_string() + fn to_matrixmarket_bytes(&self) -> Vec { + self.to_string().into_bytes() } } }; @@ -627,12 +627,12 @@ macro_rules! mm_real_impl { Ok(-self) } #[inline] - fn typename() -> &'static str { - "real" + fn typename() -> &'static [u8] { + b"real" } #[inline] - fn to_matrixmarket_string(&self) -> String { - self.to_string() + fn to_matrixmarket_bytes(&self) -> Vec { + self.to_string().into_bytes() } } }; @@ -681,12 +681,12 @@ macro_rules! mm_complex_impl { Ok(-self) } #[inline] - fn typename() -> &'static str { - "complex" + fn typename() -> &'static [u8] { + b"complex" } #[inline] - fn to_matrixmarket_string(&self) -> String { - self.re.to_string() + " " + &self.im.to_string() + fn to_matrixmarket_bytes(&self) -> Vec { + (self.re.to_string() + " " + &self.im.to_string()).into_bytes() } } }; @@ -738,13 +738,12 @@ macro_rules! mm_pattern_impl { )) } #[inline] - fn typename() -> &'static str { - "pattern" + fn typename() -> &'static [u8] { + b"pattern" } #[inline] - fn to_matrixmarket_string(&self) -> String { - // pattern type will return an empty string - String::new() + fn to_matrixmarket_bytes(&self) -> Vec { + Vec::::new() } } }; @@ -1444,34 +1443,14 @@ fn next_dense_coordinate( pub fn write_to_matrix_market_str>( sparse_matrix: &S, ) -> String { - let mut matrixmarket_string = String::new(); - - // write header - matrixmarket_string.push_str("%%matrixmarket matrix coordinate "); - matrixmarket_string.push_str(T::typename()); - matrixmarket_string.push_str(" general\n"); - - //write comment - matrixmarket_string.push_str("% matrixmarket file generated by nalgebra-sparse.\n"); - - // write shape information - matrixmarket_string.push_str(&sparse_matrix.nrows().to_string()); - matrixmarket_string.push(' '); - matrixmarket_string.push_str(&sparse_matrix.ncols().to_string()); - matrixmarket_string.push(' '); - matrixmarket_string.push_str(&sparse_matrix.nnz().to_string()); - matrixmarket_string.push('\n'); - - //write triplets - for (r, c, d) in sparse_matrix.triplet_iter() { - matrixmarket_string.push_str(&(r + 1).to_string()); - matrixmarket_string.push_str(" "); - matrixmarket_string.push_str(&(c + 1).to_string()); - matrixmarket_string.push_str(" "); - matrixmarket_string.push_str(&d.to_matrixmarket_string()); - matrixmarket_string.push_str("\n"); - } - matrixmarket_string + let mut bytes = Vec::::new(); + // This will call impl Write for Vec + // The vector will grow as needed. + // So, unwrap here won't cause any issue. + write_to_matrix_market(&mut bytes, sparse_matrix).unwrap(); + // safety issue is because 'from_utf8_unchecked' does not check that the bytes passed to it are valid UTF-8. + // Since 'bytes' created here is valid UTF-8 data, so it will not cause any problem. + unsafe { String::from_utf8_unchecked(bytes) } } /// Write a sparse matrix into Matrix Market format file. @@ -1508,38 +1487,40 @@ pub fn write_to_matrix_market_file< sparse_matrix: &S, path: P, ) -> Result<(), MatrixMarketError> { - // The code is basically the same as write_to_matrix_market_str, but write the matrix into file instead. let mut file = File::create(path)?; - - // write header - write!( - file, - "%%matrixmarket matrix coordinate {} general\n", - T::typename() - )?; - - // write comments - write!(file, "% matrixmarket file generated by nalgebra-sparse.\n",)?; - - // write shape information - write!( - file, - "{} {} {}\n", - sparse_matrix.nrows(), - sparse_matrix.ncols(), - sparse_matrix.nnz() - )?; - - // write triplets - for (r, c, d) in sparse_matrix.triplet_iter() { - write!( - file, - "{} {} {}\n", - r + 1, - c + 1, - d.to_matrixmarket_string() - )?; - } - + write_to_matrix_market(&mut file, sparse_matrix)?; + Ok(()) +} + +/// low level implementation of writing sparse matrix into any [std::io::Write] object +fn write_to_matrix_market, W: Write>( + w: &mut W, + sparse_matrix: &S, +) -> Result<(), MatrixMarketError> { + // write header + w.write_all(b"%%matrixmarket matrix coordinate ")?; + w.write_all(T::typename())?; + w.write_all(b" general\n")?; + + //write comment + w.write_all(b"% matrixmarket file generated by nalgebra-sparse.\n")?; + + // write shape information + w.write_all(sparse_matrix.nrows().to_string().as_bytes())?; + w.write_all(b" ")?; + w.write_all(sparse_matrix.ncols().to_string().as_bytes())?; + w.write_all(b" ")?; + w.write_all(sparse_matrix.nnz().to_string().as_bytes())?; + w.write_all(b"\n")?; + + //write triplets + for (r, c, d) in sparse_matrix.triplet_iter() { + w.write_all((r + 1).to_string().as_bytes())?; + w.write_all(b" ")?; + w.write_all((c + 1).to_string().as_bytes())?; + w.write_all(b" ")?; + w.write_all(&d.to_matrixmarket_bytes())?; + w.write_all(b"\n")?; + } Ok(()) }